UVa 10596 - Morning Walk, 赤裸裸的欧拉回路

FILE10596 - Morning Walk3791
37.43%
1073
89.84%

题目链接:

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=105&page=show_problem&problem=1537


题目类型: 欧拉回路, 并查集, dfs


题目:

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 blessing for him. Every morning he takes a walk through the hilly roads of charming city Chittagong. He is enjoying this city very much. There are so many roads in Chittagongand every morning he takes different paths for his walking. But while choosing a path he makes sure he does not visit a road twice not even in his way back home. An intersection point of a road is not considered as the part of the road. In a sunny morning, he was thinking about how it would be if he could visit all the roads of the city in a single walk. Your task is to help Kamal in determining whether it is possible for him or not.


题目大意:

Kamal每天早上都要从家里走到Chittagongand这个地方。 从家里到Chittagongand有很多条路, 他每天早上都要先选择好一条路线, 这条路线从家里走到Chittagongand,在从Chittagongand走回家里。 这条路线不能重复地经过同一条路。 两个地点间可能会有多条路。 比如多次出现了从A到B的路线,  那么表示每次出现的都是不同的路


分析与总结:

这题就是赤裸裸的欧拉回路。UVa 10054 - The Necklace   UVa 10129 - Play on Words    这两篇讲得较详细。 不再累赘


1. 欧拉回路+DFS

#include<cstring>
#include<iostream>
#include<cstdio>
using namespace std;
int vis[210],N, M, G[210][210], inDegree[210], outDegree[210];

void dfs(int v)         //深度优先遍历  
{  
    vis[v]=true;  
    for(int i=0;i<N;i++)  
    {  
        if(!vis[i] && G[v][i])  
        {  
            dfs(i);  
        }  
    }  
}  

int main(){
#ifdef LOCAL
    freopen("input.txt","r",stdin);
#endif
    while(~scanf("%d %d",&N, &M)){
        memset(G, 0, sizeof(G));
        int a,b;
        memset(vis, 0, sizeof(vis));
        for(int i=0; i<M; ++i){
            scanf("%d %d",&a,&b);
            G[a][b] = G[b][a] = 1;
            ++vis[a]; 
            ++vis[b];
        }
        
        int cnt = 0;
        for(int i=0; i<N; ++i){
            if(vis[i]%2==1){
                ++cnt;
                break;
            }
        }
        memset(vis, 0, sizeof(vis));
        if(cnt || M<2) printf("Not Possible\n");
        else{
            dfs(0);
            bool flag = true;
            for(int i=0; i<N; ++i) {
                if(!vis[i]) flag = false;
            }
            if(flag)printf("Possible\n");
            else printf("Not Possible\n");
        }
    
    }
    return 0;
}

2,欧拉回路+并查集

#include<cstring>
#include<iostream>
#include<cstdio>
using namespace std;
int vis[210],N, M, G[210][210], inDegree[210], outDegree[210], f[210];

void init()   //并查集判断是否是一个连通图  
{  
    int i;  
    for(i=0;i<N;i++)  
        f[i]=i;  
}  
int find(int x)  
{  
    int r=x;  
    while(f[r]!=r)  
    r=f[r];  
    f[x]=r;  
    return r;  
}  
void Union(int x,int y)  
{  
    int fx,fy;  
    fx=find(x);  
    fy=find(y);  
    if(fx!=fy)  
    f[fx]=fy;  
}  

int main(){
#ifdef LOCAL
    freopen("input.txt","r",stdin);
#endif
    while(~scanf("%d %d",&N, &M) && N){
        memset(G, 0, sizeof(G));
        int a,b;
        init();
        memset(vis, 0, sizeof(vis));
        for(int i=0; i<M; ++i){
            scanf("%d %d",&a,&b);
            ++G[a][b];
            ++G[b][a];
            ++vis[a];
            ++vis[b];
            Union(a,b);
        }
        
        int ans=0;
        for(int i=0; i<N; ++i) if(f[i]==i) ++ans;
        
        if(ans==1 && M>=2){
            int cnt = 0;
            for(int i=0; i<N; ++i){
                if(vis[i]%2==1){
                    ++cnt;
                    break;
                }
            }
            if(cnt) printf("Not Possible\n");
            else printf("Possible\n");
        }
        else
            printf("Not Possible\n"); 
    }
    return 0;
}


——      生命的意义,在于赋予它意义。 

                   原创  http://blog.csdn.net/shuangde800  , By   D_Double










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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值