【请教】acm--基于并查集

kewing 2009-08-08 12:58:03
请教HDOJ acm小希的迷宫:Problem: http://acm.hdu.edu.cn/showproblem.php?pid=1272

怎么都有问题,VC编译通过,但是运行结果不正确,自己检查不出来了……不知道是哪里的问题……还望高手指点。谢谢先~

代码如下:代码中使用了并查集来判断图是否连通。为了算法清晰,特地添加了一些注释

#include <stdio.h>
#define MAXNUM 10000
#define TRUE 1
#define FALSE 0

void link(int x,int root[]);

void main(){
int refer[MAXNUM+1]={0}; //顶点参考数组,以确定某顶点是否已经出现过
int vexs[MAXNUM]={0}; //顶点数组
int root[MAXNUM]; //各不相交树结点的最远祖先
int ivex,jvex,vexnum=0,edgenum=0;
int father;
int finished=FALSE,connected=TRUE;
int i;

for(i=0;i<MAXNUM;i++) root[i]=i; //初始化,每个顶点都分别属于一个集合

while(scanf("%d%d",&ivex,&jvex)){
if(ivex==-1&&jvex==-1) break;
if(ivex==0&&jvex==0) finished=TRUE;
if(finished){ //已完成输入,判断是否符合题意
finished=FALSE;
link(vexs[0],root); //使与vexs[0]同属于一个集合的元素以统一的标志出现
father=root[vexs[0]]; //若该图联通,则所有的顶点即位于同一个集合内
for(i=0;i<vexnum;i++){ //对个顶点进行判断
link(vexs[i],root);
if(root[vexs[i]]!=father) {connected=FALSE;break;}
}//for
if(!connected) {
printf("NO!--Because the rooms don't connect each other\n");
connected=TRUE;
}//if
else if(vexnum!=(edgenum+1)) printf("NO!--Because there are cycles!\n");
else printf("YES!\n");
for(i=0;i<MAXNUM;i++){
root[i]=i; vexs[i]=0; refer[i]=0;
}//for-再次初始化
refer[MAXNUM]=0;
}//if(finished)
else{ //继续输入数据
if(refer[ivex]==0){ //还未输入过ivex
refer[ivex]=1; vexs[vexnum++]=ivex;
}
if(refer[jvex]==0){
refer[jvex]=1; vexs[vexnum++]=jvex;
}//if
edgenum++;
link(ivex,root); link(jvex,root);
root[root[ivex]]=root[jvex]; //ivex的祖先是jvex
}//else
}//while
}//main

void link(int x,int root[]){
//将x的所在集合,即x的最远祖先的所有子孙以统一标识标注。其所有子孙i的root[i]皆为该祖先y
//意味:他们皆属于以y为根的树
int father,temp;
father=x;
while(father!=root[father]) father=root[father];
while(x!=father){
temp=root[x];
root[x]=father;
x=temp;
}//while
}//link


运行的问题是:当第一组输入是不连通或者有环的时候,即printf(NO);时,其余输入都会是不连通,提示是:don't connect;如果第一次的输入是连通的且无环,即符合题意时,会正常的printf(YES);也就是说,只要出现不符合题意的输入,则以后的输入都会是不符合题意的(尽管他们其实是符合题意的……)

真不知为什么……connected是正常初始化且在变成FALSE后再次被赋予TRUE的啊……

另,为什么MAXNUM不能是超过100000的数?int的取值范围是大于100000的啊?WHY?
...全文
468 点赞 收藏 4
写回复
4 条回复
切换为时间正序
请发表友善的回复…
发表回复

[Quote=引用楼主 kewing 的回复:]
请教HDOJ acm小希的迷宫:Problem: http://acm.hdu.edu.cn/showproblem.php?pid=1272

怎么都有问题,VC编译通过,但是运行结果不正确,自己检查不出来了……不知道是哪里的问题……还望高手指点。谢谢先~

代码如下:代码中使用了并查集来判断图是否连通。为了算法清晰,特地添加了一些注释

C/C++ code#include<stdio.h>#define MAXNUM 10000#define TRUE 1#define FALSE 0void link(int x,int root[]);void main(){int refer[MAXNUM+1]={0};//顶点参考数组,以确定某顶点是否已经出现过int vexs[MAXNUM]={0};//顶点数组int root[MAXNUM];//各不相交树结点的最远祖先int ivex,jvex,vexnum=0,edgenum=0;int father;int finished=FALSE,connected=TRUE;int i;for(i=0;i<MAXNUM;i++) root[i]=i;//初始化,每个顶点都分别属于一个集合while(scanf("%d%d",&ivex,&jvex)){if(ivex==-1&&jvex==-1)break;if(ivex==0&&jvex==0) finished=TRUE;if(finished){//已完成输入,判断是否符合题意 finished=FALSE;
link(vexs[0],root);//使与vexs[0]同属于一个集合的元素以统一的标志出现 father=root[vexs[0]];//若该图联通,则所有的顶点即位于同一个集合内for(i=0;i<vexnum;i++){//对个顶点进行判断 link(vexs[i],root);if(root[vexs[i]]!=father) {connected=FALSE;break;}
}//forif(!connected) {
printf("NO!--Because the rooms don't connect each other\n");
connected=TRUE;
}//ifelseif(vexnum!=(edgenum+1)) printf("NO!--Because there are cycles!\n");else printf("YES!\n");for(i=0;i<MAXNUM;i++){
root[i]=i; vexs[i]=0; refer[i]=0;
}//for-再次初始化 refer[MAXNUM]=0;
}//if(finished)else{//继续输入数据if(refer[ivex]==0){//还未输入过ivex refer[ivex]=1; vexs[vexnum++]=ivex;
}if(refer[jvex]==0){
refer[jvex]=1; vexs[vexnum++]=jvex;
}//if edgenum++;
link(ivex,root); link(jvex,root);
root[root[ivex]]=root[jvex];//ivex的祖先是jvex }//else }//while}//mainvoid link(int x,int root[]){//将x的所在集合,即x的最远祖先的所有子孙以统一标识标注。其所有子孙i的root[i]皆为该祖先y//意味:他们皆属于以y为根的树int father,temp;
father=x;while(father!=root[father]) father=root[father];while(x!=father){
temp=root[x];
root[x]=father;
x=temp;
}//while}//link

运行的问题是:当第一组输入是不连通或者有环的时候,即printf(NO);时,其余输入都会是不连通,提示是:don't connect;如果第一次的输入是连通的且无环,即符合题意时,会正常的printf(YES);也就是说,只要出现不符合题意的输入,则以后的输入都会是不符合题意的(尽管他们其实是符合题意的……)问题1 finished里面重新初始化时少了两项vexnum=0;edgenum=0;

真不知为什么……connected是正常初始化且在变成FALSE后再次被赋予TRUE的啊……

另,为什么MAXNUM不能是超过100000的数?int的取值范围是大于100000的啊?WHY?

函数里分配一定大小的栈空间。如果申请数组超过这空间当然就会报错。用全局变量就好了。

并查集的算法还是有问题的。
调试了好一会,还是不清楚在哪里。包括root[]何vetx[]下标不全对应

[/Quote]
回复
kewing 2009-08-09
真雷人……每次都是因为小问题导致程序运行不正确,上次有道也是,因为数组分配不够导致运行不正确……满头黑线……
回复
kewing 2009-08-09
哈哈哈~~~果然是忘了重新给vexnum和edgenum赋值……现在运行OK了~谢谢楼上!另,并查集的算法应该没有问题……root[]和vexs[]的下标不是对应关系,root是完全独立于vexs[]的。
回复
baihacker 2009-08-08

//可以用下面的代码AC
//注意几点
//一输入就是0 0的情况
#include <iostream>
#include <cstring>
#include <map>
#include <cstdio>
using namespace std;

int p[100000];
void link(int x, int y)
{
if (x == y) return;
if (p[x] < p[y])
{
p[y] = x;
}
else
{
int t = p[x] == p[y];
p[x] = y;
p[y] -= t;
}
}
int find(int x)
{
int r = x;
while (p[r] > 0) r = p[r];
while (x != r){int s = p[x]; p[x] = r; x = s;}
return r;
}

void merge(int x, int y)
{
link(find(x), find(y));
}
int main()
{
for (;;)
{
int u, v;
scanf("%d%d", &u, &v);
if (u < 0) break;
if (u == 0) {puts("Yes");continue;}
memset(p, 0, sizeof(p));
map<int, int> mp;
int edge_count = 1;
int ok = 1;
++mp[u], ++mp[v];
merge(u, v);
if (u != v)
for (;;)
{
scanf("%d%d", &u, &v);
if (u == 0) break;
if (find(u) == find(v))
{
ok = 0;
break;
}
++edge_count;
merge(u, v);
++mp[u], ++mp[v];
}
else ok = 0;
while (u) scanf("%d%d", &u, &v);
if (ok == 1 && mp.size() - 1 == edge_count) puts("Yes");
else puts("No");
}
return 0;
}
回复
发动态
发帖子
数据结构与算法
创建于2007-08-27

3.2w+

社区成员

数据结构与算法相关内容讨论专区
申请成为版主
社区公告
暂无公告