UVa 10596 清晨漫步

来源:互联网 发布:故事软件下载 编辑:程序博客网 时间:2024/05/01 23:15

题意:有很多路,问能否每条路只走一遍、恰好回到起点?

思路:无向图的欧拉回路的应用。但是是神坑的一道题~  

注意:考虑下面的数据

Input:
3 2
0 1
1 0

2 2
1 0
1 0

4 4
0 1
1 0
2 3
3 2

5 6
0 1
1 0
2 3
2 3
0 2
2 0

4 6
1 2
2 1
2 3
2 3
3 1
1 3

2 0

Output:
Possible
Possible
Not Possible
Possible
Possible
Not Possible

也就是说,第一,只要把所有的边访问就行了,可以存在一些没有访问的顶点。

第二,r==0时是Not Possible的(没有路径时就不能访问所有的边,因为没有边可访问;但是没有路径时也等于可以访问所有的边,因为没有边是没有访问的。。感觉和第一条的逻辑有些矛盾!!)

第三,输入数据可能存在自回路,也就是 1 1这样的边,它是考虑到有一条路是圆形的吗??(这个导致了版本一的RE错误)

总结:输入无向边,graph[u][v]++; graph[v][u]++; (不要用graph[v][u]=graph[u][v]; 因为对自回路错误。)  修改相应顶点的度数

            删除无向边,graph[u][v]--; graph[v][u]--;

反正就是感觉数据太坑了~~

首先,提交的是版本一,在判断连通性时,我没有用vis数组来判断一个顶点是否访问过,而是用顶点的度数是否为0来判断,因为每次访问一条边后、删除这条边时会减少相应顶点的度数。但是在输入时我用的graph[u][v]++;graph[v][u]=graph[u][v]; 提交后RE错误,由于题目在终止输入时没有说清,改了几次输入如下代码所示,变成了WA。

Code:

//版本一,AC#include<stdio.h>#include<string.h>void dfs(int u,int n);bool solve(int n);int du[205];int graph[205][205];int main(){  int n,r;  //scanf("%d%d",&n,&r);  //while(scanf("%d%d",&n,&r)==2 && n && r)  while(scanf("%d%d",&n,&r)==2)  {    memset(du,0,sizeof(du));    memset(graph,0,sizeof(graph));    for(int i=0;i<r;++i)    {      int u,v;      scanf("%d%d",&u,&v);      graph[u][v]++;      //graph[v][u]=graph[u][v];      graph[v][u]++;      du[u]++;      du[v]++;          }    if(solve(n)) printf("Possible\n");    else printf("Not Possible\n");                    }  return 0;}bool solve(int n){  for(int i=0;i<n;++i)  {    if(du[i]&1) return false;  }      int cnt=0;  for(int i=0;i<n;++i)  {    if(du[i])    { cnt++; dfs(i,n);}        }//printf("cnt:%d\n",cnt);  if(cnt!=1) return false;  return true;}void dfs(int u,int n){  for(int v=0;v<n;++v)  {    if(graph[u][v])    { //删除无向边      graph[u][v]--;      graph[v][u]--;       du[u]--;      du[v]--;      dfs(v,n);                 }        }   }
版本二:版本二在判断连通性时,不是用dfs数总共的连通分量个数了,而是一遍dfs后看是否有结点未访问,WA了。(这里也是在访问边时修改顶点的度数,最后用顶点的度数判断顶点是否访问过。)不过这一版本的调试,发现了如果在输入时用graph[u][v]++; graph[v][u]=graph[u][v];程序会崩溃,原因是如果有顶点的自回路,则上述语句的真正意思错了,而是应该用graph[u][v]++; graph[v][u]++; (不过因为这两种方式都提交了,都得到了WA,所以没有想到版本一的RE正是这个原因!!!) 版本一的输入部分,由前者改为了后者,则AC了,如上述代码所示。     (写版本二的原因是,看了网上一个用这种方式判断连通性的,而且实在想不通版本一的错误在哪。  但是最后试了下,参考的那个代码竟然是WA的。。。可能该题后来re-judge了。。)
//WA,别再修改 #include<stdio.h>#include<string.h>void dfs(int u,int n);bool solve(int n);int du[205];int graph[205][205];int main(){  int n,r;  //scanf("%d%d",&n,&r);  //while(scanf("%d%d",&n,&r)==2 && n && r)  while(scanf("%d%d",&n,&r)==2)  {    memset(du,0,sizeof(du));    memset(graph,0,sizeof(graph));    for(int i=0;i<r;++i)    {      int u,v;      scanf("%d%d",&u,&v);      graph[u][v]++;      //graph[v][u]=graph[u][v];      graph[v][u]++;//自回路       du[u]++;      du[v]++;          }    if(solve(n)) printf("Possible\n");    else printf("Not Possible\n");                    }  return 0;}bool solve(int n){  for(int i=0;i<n;++i)  {    if(du[i]&1 || du[i]==0) return false;  }      dfs(0,n);  for(int i=0;i<n;++i)  { if(du[i]) return false; }   return true;}void dfs(int u,int n){  for(int v=0;v<n;++v)  {    if(graph[u][v])    { //删除无向边      graph[u][v]--;      graph[v][u]--;       du[u]--;      du[v]--;      dfs(v,n);                 }        }   }
版本三:版本三是在版本二的基础上修改。版本二的错误一在于,dfs(0)的错误。因为0号顶点可能是没有边的。错误二在于,r==0时是Not Possible的。
<pre name="code" class="cpp">//AC#include<stdio.h>#include<string.h>void dfs(int u,int n);bool solve(int n);int du[205];int graph[205][205];int vis[205];int main(){  int n,r;  //scanf("%d%d",&n,&r);  //while(scanf("%d%d",&n,&r)==2 && n && r)  while(scanf("%d%d",&n,&r)==2)  {    memset(du,0,sizeof(du));    memset(graph,0,sizeof(graph));    memset(vis,0,sizeof(vis));    for(int i=0;i<r;++i)    {      int u,v;      scanf("%d%d",&u,&v);      graph[u][v]++;      //graph[v][u]=graph[u][v];      graph[v][u]++;//自回路       du[u]++;      du[v]++;          }    if(r && solve(n)) printf("Possible\n");    else printf("Not Possible\n");                    }  return 0;}bool solve(int n){  for(int i=0;i<n;++i)  {    if(du[i]&1) return false;  }      for(int i=0;i<n;++i)  {    if(du[i])    {      vis[i]=1;      dfs(i,n);      break;           }        }  for(int i=0;i<n;++i)  { if(du[i] && !vis[i]) return false; }   return true;}void dfs(int u,int n){  for(int v=0;v<n;++v)  {    if(!vis[v] && graph[u][v])    {       vis[v]=1;       dfs(v,n);    }        }   }

另外,据说只要判断每个顶点的度数是否为偶数以及 r 是否等于 1 就可以了,没试过。。

0 0
原创粉丝点击