UVa 10596 清晨漫步

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

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

注意:考虑下面的数据

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错误)

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

首先,提交的是版本一,在判断连通性时,我没有用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 就可以了,没试过。。

时间: 2024-11-22 18:38:48

UVa 10596 清晨漫步的相关文章

UVA - 10596 - Morning Walk (欧拉回路!并查集判断回路)

UVA - 10596 Morning Walk Time Limit: 3000MS Memory Limit: Unknown 64bit IO Format: %lld & %llu Submit Status Description Problem H Morning Walk Time Limit 3 Seconds Kamal is a Motashota guy. He has got a new job in Chittagong . So, he has moved to Ch

uva 10596 Morning Walk (欧拉回路)

uva 10596 Morning Walk Kamal is a Motashota guy. He has got a new job in Chittagong . So, he has moved to Chittagong from Dinajpur. He was getting fatter in Dinajpur as he had no work in his hand there. So, moving to Chittagong has turned to be a ble

uva 10596 - Morning Walk

Problem H Morning Walk Time Limit 3 Seconds Kamal is a Motashota guy. He has got a new job in Chittagong. So, he has moved to Chittagong from Dinajpur. He was getting fatter in Dinajpur as he had no work in his hand there. So, moving to Chittagong ha

uva 10596 欧拉回路

判断是否存在欧拉回路只要两个条件 图连通,不存在奇度点 注意特判边为0的情况.另外这题数据坑. #include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn=208;struct fuck{ int u,v,next;}edge[maxn*maxn];int head[maxn];int tol;void init(){ tol=0; memset(head,

UVa 10596 Moring Walk【欧拉回路】

题意:给出n个点,m条路,问能否走完m条路. 自己做的时候= =三下两下用并查集做了交,WA了一发-后来又WA了好几发--(而且也是判断了连通性的啊) 搜了题解= = 发现是这样的: 因为只要求走完所有的路,即为只需要走完已经给出的路,而并没有要求所走得路上含有所有的点, 比如说 给出的路有这些 0 1 1 2 2 3 3 0 4 4 那么构成的路即为,绕着图中的蓝色线走一圈,即为走完了所有的路, 而4是一个孤立点,也并没有构成路,所以不需要管它 代码中的 if(d[i]!=0)是判断这个点是否

uva 10596 Morning Walk(欧拉回路)

这道题是神坑啊,花了我将近3个小时,本来敲的挺顺的,交上去就是wa,坑点真坑,原来是有的路口交叉点可以没有 路通向它,无语,没有路通向也可以叫交叉点....以后一定得考虑多种情况,用了bfs(vector做的)和dfs判断 的是否连通,判断连通之后只需要再判断是否都有偶数个度就ok了,坑,真坑. bfs代码: #include<stdio.h> #include<string.h> #include<stdlib.h> #include<vector> #i

UVa 10917 林中漫步

https://vjudge.net/problem/UVA-10917 题意: 给出一个图,求出从1走到2共有多少种走法.前提是他只沿着满足如下条件的道路(A,B)走:存在一条从B出发回家的路径,比所有从A出发回家的路径都短. 思路: 首先用Dijkstra算法求出每个点到家的最短路径,那么题目的要求也就变成了d[B]<d[A],这样,我们创建了一个新的图,当且仅当d[B]<d[A]时加入有向边A->B,这样就是一个DAG,直接用动态规划计数. 1 #include <iostr

AOAPC-I: 算法竞赛入门经典 UVa 习题集分类

数据结构基础 UVa 10004 二染色:二部图的判定.(bfs或dfs遍历的过程进行染色,看是否有冲突) UVa 10129 单词:有向图的欧拉道路. UVa 10054 项链:无向图的欧拉回路,首尾相接输出路径. UVa 10596 清晨漫步:无向图的欧拉回路. (对于欧拉道路或回路,在判断连通性等时注意先 if 下要访问的顶点是否出现.)

UVA 562 Dividing coins --01背包的变形

01背包的变形. 先算出硬币面值的总和,然后此题变成求背包容量为V=sum/2时,能装的最多的硬币,然后将剩余的面值和它相减取一个绝对值就是最小的差值. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define N 50007 int c[102],d