简单二分图的应用

题目链接

  • 题目描述:我们把一个城市考虑为一个图, 街道为边, 路口为点. 路口标记为 0~N-1. 盗贼从一个点开始逃亡, 每一分钟走一条边. 不幸的是, 我们并不知道他逃往何处, 只能假设他每分钟都必须沿着一条边走, 不能停留但是可以反复经过. 警官想要知道是否存在一个时刻, 盗贼可能出现在城市中的任意路口.
  • 输入描述:第一行, 整数T, 测试用例数. 每例第一行3个整数, 点数N<=1e5, 边数M<=5e5, 起点S. 接下来M行, 每行两个数字表示一条边.
  • 输出描述:如果存在这样的时刻输出"YES", 否则"NO".
  • 测试案例:
  • 输入:
    2
    3 3 0
    0 1
    0 2
    1 2
    2 1 0
    0 1
  • 输出:
    Case 1: YES
    Case 2: NO
  • 题目分析与思考:图与起点,题目已告知,从起点出发,它到达每一个节点可能有很多种情况,有可能是奇数时间到达,也有可能是偶数时间到达,题目询问你是否有一个时刻使它可以到达任意地点,时刻是不确定,但是这个时刻必然是偶数时间奇数时间中的一种。题目提醒我们每一条路可以多次经过,也就是说,边可以经过任意次数,那有没有一种可能,我们第一次到达一个地点是偶数时间,经过探寻又回到这个地方,探寻的过程,应该经历图中的一个环,不过此的时时间是奇数时间,这时你就会发现,任意一个节点,经过这个环的调节,都能在固定的时间到达。原理:这个环,一次经过需要奇数时间,那么,想要奇数时间,就遍历奇数次,想要偶时间,就经历偶数次。这样这个题目的中心要求就一目了然了,就是判断这个图中是否存在奇数的环,不过判断之前,首先确定这个图是连通的。
  • 二分图的定义: 二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。
  • 二分图含有的隐含特征:根据定义,你可以查看任意一个图,会发现含有奇数节点的环的图不可能为二分图,因此二分图是不含有奇数的环。
  • 采用二分图染色原理判断是否含有奇数环;
  • #include<stdio.h>
    #include<algorithm>
    #include <vector>
    using namespace std;
    #include <string.h>
    #define maxn 100005
    int n,m,s,flag,ans[maxn];
    vector<int>Q[maxn];
    void dfs(int x)
    {
        for(int i = 0; i<Q[x].size(); i++)
        {
            int y = Q[x][i];
            if(ans[y]==-1)
            {
                ans[y] = ans[x]^1;
                dfs(y);
            }
            else if(ans[y]==ans[x])
            {
                flag = 1;
                return ;
            }
        }
        return ;
    }
    int main()
    {
        int t,Case=1;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d %d %d",&n,&m,&s);
            for(int i=0; i<maxn-1; i++)
                Q[i].clear();
            int x,y;
            int in[maxn];
            memset(in,0,sizeof(in));
    
            for(int i=0; i<m; i++)
            {
                scanf("%d %d",&x,&y);
                in[x]++;
                in[y]++;
                Q[x].push_back(y);
                Q[y].push_back(x);
            }
    		int kmp  = 0 ;
            for(int i=0; i<n; i++)
                if(in[i]==0)
                {
                    kmp = 1;
                    break;
                }
            printf("Case %d: ",Case++);
            memset(ans,-1,sizeof(ans));
            flag = 0;
            dfs(s);
            if(!flag||kmp)
                puts("NO");
            else puts("YES");
        }
        return 0;
    }
    

     

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值