zoukankan      html  css  js  c++  java
  • [Codeforces 19E] Fiary

    Brief Intro:

    给定一个无向图,询问删去哪条边能使得剩下的图为一个二分图,输出所有结果

    Algorithm:

    关于二分图的重要性质:一个图为二分图的充要条件为其中没有奇环

    1、如果没有奇环,那么删去任何一条边都不会使其变为奇环

    2、如果存在一个或多个奇环,删去的边必为所有奇环的一条公共边

       但这样仍然无法保证残余图是一个二分图:因为有偶环的存在

          

          为了寻找奇环或者偶环,我们一般采取dfs树的方式

          我们可以证明(奇偶性判断即可)当一个环上有两个偶返祖边或两个奇返祖边时,这个环必为偶环

          而当一个环上有一个奇返祖边以及一个偶返祖边时,这个环必为奇环

          如果一条边有一个奇环以及一个偶环通过,那么删去这条边后一定会出现一个环中包含一个奇返祖边和一个偶返祖边

          从而出现奇环,不成立

    题目被转化为:求出既是所有奇环公共边又不在任何一个偶环中的边

    dfs树维护每条边经过的奇/偶环个数即可

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef pair<int,int> P;
    typedef long long ll;
    #define F first
    #define S second
    
    const int MAXN=1e4+10;
    int n,m,odd[MAXN],even[MAXN],vis[MAXN],match[MAXN],col[MAXN],st,cnt;
    vector<P> G[MAXN];
    vector<int> res;
    
    void dfs(int cur,int anc)
    {
        vis[cur]=1;col[cur]=col[anc]^1;
        for(int i=0;i<G[cur].size();i++)
        {
            P t=G[cur][i];
            if(t.F==anc) continue;
            if(!vis[t.F])  //将点和其父边配对
                match[t.F]=t.S,dfs(t.F,cur),odd[cur]+=odd[t.F],even[cur]+=even[t.F];
            else if(vis[t.F]==1)
                col[cur]==col[t.F]?odd[cur]++,st=t.S,cnt++:even[cur]++;
            else
                col[cur]==col[t.F]?odd[cur]--:even[cur]--; //如果到了一个环的起始点,那么该点的父边不在环中
        }
        vis[cur]=-1;  //不同的标记
    }
    
    int main()
    {
        cin >> n >> m;
        for(int i=1;i<=m;i++)
        {
            int x,y;cin >> x >> y;
            G[x].push_back(P(y,i));G[y].push_back(P(x,i));
        }
        
        for(int i=1;i<=n;i++)
            if(!vis[i])
                dfs(i,0);
                
        if(cnt==0)
            for(int i=1;i<=m;i++) res.push_back(i);
        else
        {
            if(cnt==1) res.push_back(st);  //如果只有一个奇环,起始边也符合条件
            for(int i=1;i<=n;i++)
                if(odd[i]==cnt && !even[i]) res.push_back(match[i]);
            sort(res.begin(),res.end());
        }
        
        cout << res.size() << endl;
        for(int i=0;i<res.size();i++)
            cout << res[i] << " ";
        
        return 0;
    }

    Review:

    1、二分图的充要条件:不含奇环

         同时不用考虑原图中的所有环,而只要考虑dfs树构造出的环即可

    2、可采用dfs树的方式计算图中的奇、偶环

          注意对一个环起始点的特殊处理

    (UPD:实际上这是一个$dfs$树上差分的过程)

    3、由于dfs树的无后效性,如果一个大环中包含两条返祖边,去掉两小环的公共路径*2,不改变两小环总和的奇偶性,从而能推断出大环的奇偶性

          利用dfs树中的迭代性、公共路径推出有用的结论

    4:注意很多时候只要考虑$dfs$返祖边的环即可!!!!

  • 相关阅读:
    some Rails leanrning:Rails Ajax,Validates,Cycle
    快速排序与挑白菜
    九月开学
    搜索引擎代码资源
    start RubyOnRails
    垂直搜索引擎之我见
    demo下载:ASP.NET GDI+生成动态的Gif动画
    NHibernate和ADO.Net的性能对比相差有多大?
    手工调试自定义控件各主要方法执行顺序(分运行时和设计时)
    ASP.Net中的缓存方案(不仅仅是Cache和Session)(我在CSDN上和别人的争论)
  • 原文地址:https://www.cnblogs.com/newera/p/9034794.html
Copyright © 2011-2022 走看看