uva 10054 - The Necklace 惨痛经历

做了两天,一直在用bfs来做dfs的题,于是就一直TLE到死。以为邻接矩阵不够快,改用邻接表,但是还是TLE。直到怀疑服务器挂有问题= =,上网找别人的代码交。第一个找到的交上去还是错的,直到找到这个参考代码出处

于是就仿照写一两次,终于发现了几处写错的地方。(其实是发现bfs和dfs的区别)


是什么:把每个珠子看出一条边,珠子的两种颜色看成点。就是给出所有的边(无向)看看能不能找到欧拉回路(就是一笔画,起点和终点同是一个点)(而起点和终点不在一个点上的一笔画就是欧拉道路)


为什么图的转换,把某些关系转化成边,点。解除是否存在什么什么的路径(方法),什么什么的最短路径(最优方法)。


怎么样要知道存在欧拉回路的图,不管从哪一个点出发,都能顺利完成“一笔画”(证明:既然能够一笔画完整个图而回到起点,那可以把图看成一个圆,那在圆上选任意一点都能完成一笔画)。所以判断是不是欧拉回路接下来输出路径就简单了(可对于我来说,并不是T_T)。

    而判断无向图是否为的欧拉回路有两个方面:

1,图是否联通的。

2,每个点的是否有偶数条边相连。

   第 1 点直接用并查集做。

   第 2 点在加入边时直接计算就是了。


以下是代码:

这是邻接矩阵的

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
int fa[60];
int data[60][60];
int findfa(int i){
	if(fa[i]==i) return fa[i];
	fa[i]=findfa(fa[i]);
	return fa[i];
}
void eur(int k){
	for(int i=1;i<60;++i){
		if(data[k][i]){
			--data[k][i];
			--data[i][k];
			printf("%d %d\n",k,i);
			eur(i);
			
			//break;//这个不能加!
		}
	}
}
int main(){
	int cas;
	scanf("%d",&cas);
	for(int casi=1;casi<=cas;++casi){
		for(int i=0;i<60;++i)
			fa[i]=i;
		memset(data,0,sizeof(data));
		int n;
		scanf("%d",&n);
		int a,b;
		for(int i=0;i<n;++i){
			scanf("%d%d",&a,&b);
			int tmp=min(a,b);
			b=a+b-tmp;
			a=tmp;
			++data[a][b];
			++data[a][0]; //<span style="font-family: 'Microsoft YaHei';">计算和点连接的边的数量</span>
			++data[b][a];
			++data[b][0]; //也是<span style="font-family: 'Microsoft YaHei';">计算和点连接的边的数量</span>
			if(findfa(a)!=findfa(b))
				fa[findfa(b)]=findfa(a);
		}
		int flag=0,sta;
		for(int i=1;i<60;++i){
			if(data[i][0]%2) flag=1;
			if(data[i][0]) sta=i;
		}

		for(int i=1;i<60;++i)
			if(data[i][0]&&findfa(i)!=findfa(sta)) flag=1;

		printf("Case #%d\n",casi);
		if(flag){
			printf("some beads may be lost\n");
			if(casi!=cas) printf("\n");
			continue;
		}
		eur(sta);
		if(casi!=cas) printf("\n");
	}
	return 0;
}

而这是邻接表写的

#include<iostream>
#include<cstdio>
#include<cstring>
using  namespace std;
struct node{
	int start,index;
	int tot;
	int upp;
	int fa;
	node(int i=0,int inndex=0){
		index=i;
		start=-1;
		upp=-1;
		tot=0;
		fa=inndex;
	}
};
node nda[110];

struct edge{
	int next;
	int sta,end;
	int up;
	int use;
	edge(int a=0,int b=0,int c=0){
		sta=a;
		end=b;
		use=0;
		next=nda[a].start;
		nda[a].start=c;
	}
};

edge eda[16000];
int find(int a){
	if(nda[a].fa==a) return a;
	nda[a].fa=find(nda[a].fa);
	return nda[a].fa;
}
void gotofind(int stain){
	for(int x=nda[stain].start;x!=-1;x=eda[x].next){
		if(eda[x].use==0){
			eda[x].use=1;
			eda[x^1].use=1;
			stain=eda[x].end;
		      //cout<<eda[x].sta<<' '<<eda[x].end<<endl;
                                                  /*
<span style="white-space:pre">							</span>这个不能卸载递归前面,因为当递归结束回到这里输出的答案和题目要求不一样
<span style="white-space:pre">							</span>可是又觉这样说不过去,不符合欧拉回路的性质啊。。。好纠结,知道的留个言~谢谢啦!
<span style="white-space:pre">						</span>   */
			gotofind(stain);

			cout<<eda[x].end<<' '<<eda[x].sta<<endl;
		}
	}
}

int main(){
	int cas;
	cin>>cas;
	for(int casi=1;casi<=cas;++casi){
		for(int i=0;i<55;++i){
			node ini(0,i);
			nda[i]=ini;
		}
		int n;
		scanf("%d",&n);
		int maxin=-1;
		int ai,bi;
		int k=0,sum=0;
		for(int i=1;i<=n;++i){
			scanf("%d%d",&ai,&bi);
			edge tmp(ai,bi,k);
			eda[k]=tmp;
			++k;
			
			edge tmp1(bi,ai,k);
			eda[k]=tmp1;
			++k;
			
			++nda[ai].tot;
			++nda[bi].tot;

			maxin=max(maxin,ai);
			maxin=max(maxin,bi);

			int t1=find(nda[ai].fa),t2=find(nda[bi].fa);
			if(t1!=t2)
				nda[t1].fa=t2;
			
			++sum;
		}
		int flag=0,stain=0,maxto=-1;
		for(int i=1;i<=maxin;++i){
			if(maxto<nda[i].tot){
				maxto=nda[i].tot;
				stain=i;
			}
			if(nda[i].tot%2)
				flag=1;
		}
		int tfa=find(stain);
		for(int i=0;i<=55;++i){
			if(nda[i].tot&&tfa!=find(i)) flag=1;
		}
		cout<<"Case #"<<casi<<endl;
		if(flag){
			cout<<"some beads may be lost"<<endl;
			if(casi!=cas) cout<<endl;
			continue;
		}
		gotofind(stain);

		if(casi!=cas) cout<<endl;
	}
	return 0;
}


关于dfs和bfs的应用区别(我的理解)是:

bfs:用于找最优

dfs:用于找有无

但是算法杀死很灵活的,并不是固定不变的。需要看情(xin)况(qing)使用





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值