博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
sgu 101 domino
阅读量:7073 次
发布时间:2019-06-28

本文共 2672 字,大约阅读时间需要 8 分钟。

    题意还算简洁明了,加上有道翻译凑过着读完了题。题意大体上是 给你 个多米诺骨牌, 给出每个骨牌两端的数字, 只有数字相同才可以推到, 比如 2-3和3-2。你可以旋转这些多米诺骨牌, 输出一个可以全部推到的方案, 如果没有 ,输出 No solution。

    第一眼看上去像爆搜, 但是 n 最大到100, 时限竟然只有0.25s,铁定超时, 换个思路, 想不出来, 看了题解,才发现原来是图论题,我们把 0~6 当做点,把每个骨牌当做边, 这样构成了一个图, 我们需要求得就是 遍历所有的边且不重复

    这个可以算是一个 欧拉路 模板题,注意,是 欧拉路, 不是欧拉回路 ,被坑了好久。

    欧拉路和欧拉回路都是一笔画问题, 两者都需要满足一个必要条件 : 度数为奇数的要么没有, 要么有2个。 度数就是这个点连得边的条数。

    先说欧拉回路, 欧拉回路由于需要回到原点, 所以一定没有度数为奇的点, 只要从任意一点 dfs ,走过的边不再走, 直到无边可走, 就是欧拉回路,此时一定是在原点。

    但是,欧拉路不同, 欧拉路可以不回到原点, 这导致 dfs 有可能导致死胡同 , 看一个例子 :

在这个例子里, 如果从 3 开始 dfs, 我们有可能回走到 2 ,然后走到 1, 这时我们发现无路可走了, 但这本应是一个一笔画, 只要从 1 出发就可以了,但是我们在程序里不好判断从哪个点开始, 所以, 引入欧拉路的求法:

    从任意一个度数为奇的点开始,仍然 dfs,但是 我们不一开始就把这个点加入答案, 而是先任选和这个点相连的一条边, 继续向下dfs, 然后在把这个店加入答案,就等于是倒序输出。这样很巧妙的解决了上面说的问题。光这么说可能不太好理解,一看代码立刻就能明白。

void ss(int now){    遍历每一条和这个点相连的边     {        标记已经走过这条边,以后不再走                ss(和它相邻的点);        把现在这个点加入答案    }}

    如此一来就可以了, 但要注意,要判断此图是否联通, 只需判断你求出的边数和骨牌数是否相等就行了,上代码:

#include 
#include
#include
#include
#include
#define N 110 * 2#define M 10using namespace std;int n, du[M] = {
0};int p[M], next[N*2], v[N*2], zheng[N*2], bnum = -1, kexing[N*2], num[N*2];int ans[N][2], ansnum = 0;void addbian(int x, int y, int now){ bnum++; next[bnum] = p[x]; p[x] = bnum; v[bnum] = y; zheng[bnum] = 1; kexing[bnum] = 1; num[bnum] = now; bnum++; next[bnum] = p[y]; p[y] = bnum; v[bnum] = x; zheng[bnum] = 0; kexing[bnum] = 1; num[bnum] = now;}void ss(int now){ int k = p[now]; while (k != -1) { if (kexing[k]) { kexing[k] = 0; kexing[k^1] = 0; ss(v[k]); ansnum++; ans[ansnum][0] = num[k^1]; ans[ansnum][1] = zheng[k^1]; } k = next[k]; }}int main(){ scanf("%d", &n); for (int i = 0; i <= 6; ++i) p[i] = -1; for (int i = 1; i <= n; ++i) { int x, y; scanf("%d%d", &x, &y); du[x]++; du[y]++; addbian(x, y, i); } if (n == 0) { printf("No solution\n"); return 0; } int jnum = 0, start = -1; for (int i = 0; i <= 6; ++i) if (du[i] % 2 != 0) { jnum++; start = i; } if (jnum !=0 && jnum != 2) { printf("No solution\n"); return 0; } if (start == -1) for (int i = 0; i <= 6; ++i) if (du[i] != 0) start = i; ss(start); if (ansnum < n) { printf("No solution\n"); return 0; } for (int i = 1; i <= n; ++i) { printf("%d ",ans[i][0]); if (ans[i][1]) printf("+\n"); else printf("-\n"); }}

 

转载于:https://www.cnblogs.com/handsomeJian/p/3729904.html

你可能感兴趣的文章
HTML5的布局的使用
查看>>
hdu 1068 二分图的最大匹配匈牙利算法
查看>>
一个IT人的非典型职场十年 (4)
查看>>
Netty之Recycler实现对象池
查看>>
Netty5入门学习笔记004-使用Netty传输POJO对象(上)
查看>>
Eclipse的快捷键总结
查看>>
RandomAccessFile相关(读写文件) --本文的正确性有待您验证。
查看>>
实现SPF垃圾邮件防护功能
查看>>
Slave IO: Yes Slave SQL: No Seconds Behind Mast...
查看>>
eclipse 使用Maven deploy命令部署构建到Nexus上
查看>>
大型系统中使用JMS优化技巧–Sun OpenMQ
查看>>
正则表达式-断言
查看>>
用git合并分支时,如何保持某些文件不被合并
查看>>
局部代码块、构造代码块、静态代码块
查看>>
聚类分析 ---- K-Means算法
查看>>
C語言最新標準-C11 「轉」
查看>>
SaltStack数据系统-Grains详解
查看>>
课程第三天内容《基础交换 三 》
查看>>
Spring(八):缓存
查看>>
全局函数指针作为模板参数
查看>>