看来自己的知识水平还是很低的,需要更多的更大量的学习才行。
很容易想到建边图找欧拉回路。
然后死于不会找欧拉回路。
存在欧拉回路==从任意一点出发都能找到欧拉回路!=随便走都能走出欧拉回路。
因为走着走着出现了桥这种东西,就不能随便走了,如果走了就一去不复还了。
尝试用随便走+贪心,但是没法解决的。
记得以前在《算法与数据结构》上看到要先找桥,然后如果不是万不得已就不要选桥。找桥还要用tarjan,妈呀,这也太麻烦了吧。
果然有很棒的解决方法。
紫书P169上的模板代码。
递归然后逆序输出保证每次都能回到当前节点。
而不是主动出去找。
思路十分巧妙。
几个需要注意的地方:
①欧拉回路是每条边恰走一次,本题是每个珍珠恰用一次,所以要把珍珠当成边,颜色当成点,然后建图。
②珍珠可以翻转,所以图是无向图。
③本题没说珍珠不重复,说明建的图是可能有重边的,所以不能只标记连通,还要标记有多少次连通。
④无向图存在欧拉回路的充要条件是图连通且各点度数为偶数。别忘了检验图连通。只不过本题没有卡你这个罢了。
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 55;
const int maxm = 1010;
int M;
int de[maxn];
int MAP[maxn][maxn];
void euler(int u)
{
for(int v=0;v<maxn;v++) if(MAP[u][v])
{
MAP[u][v]--;
MAP[v][u]--;
euler(v);
printf("%d %d\n",v,u);
}
}
bool ok()
{
for(int i=0;i<maxn;i++)
if(de[i]&1)
return false;
return true;
}
void print()
{
int now=0;
while(!de[now]) now++;
euler(now);
}
int main()
{
int T,u,v;
scanf("%d",&T);
for(int t=1;t<=T;t++)
{
memset(de,0,sizeof(de));
memset(MAP,0,sizeof(MAP));
scanf("%d",&M);
while(M--)
{
scanf("%d %d",&u,&v);
de[u]++;
de[v]++;
MAP[u][v]++;
MAP[v][u]++;
}
printf("Case #%d\n",t);
if(ok()) print();
else puts("some beads may be lost");
if(t<T) puts("");
}
return 0;
}