• Codeforces 1354E(Graph Coloring,二分图+dp)


    题意:给你n1个1,n2个2,n3个3以及n和顶点(保证n=n1+n2+n3),m条双向边。然后构成一个图,此图可能为非连通图,对该图进行染色(可以染1或2或3三种颜色),每相邻两个点颜色大小绝对值之差为1,问能否染成功?如果成功,输出每个点的染色方案。

    难度系数:图论2100

    解法:在比赛的时候直接去看的这个题,没写出来。那时候想到了以下几点:把1和3看成1(因为1和3本身不可能相连,所以看成一体)这是一个二分图,保证二分图条件后进行染色,然后因为有多个连通块构成,这时候我们把每一层的图转化成树,然后统计每一个连通块位于单数层的总结点数量cnt1,和双数层总结点数量cnt2,。然后dfs构造多个连通块再回溯结果,这么做最后TLE了。

    不过想法还是对了一半,这个dfs用背包dp代替就不会出现那种情况。用dfs去对每一个连通块建树,并标记深度,在图中如果有环的边数为奇数,显然就不是二分图。可以直接输出NO返回结果。

    开一个二维dp数组,dp[i][j],i表示是第几个连通块,j表示当前使用过的节点数量。dp为PII型,方便日后回溯搭配点。first用来记录转移之前一共拥有的数量,second表示当前选取了该连通块的奇数层还是偶数层,0表示奇数层,1表示偶数层

    开一个两层的vector<vector<int>>odd,even.odd用来记录每一个连通块所有奇数层一共有的结点数量。even用来记录偶数节点数量。

    因为有可能会出现n2等于0的情况或者n1+n3=0的情况,所以初始化dp的时候全部初始化成-1(memset(dp,-1,sizeof(dp));

    接下来分析状态转移方程。考虑dp[0][odd[0].size()]为一开始的状态,他里面所含的节点大小j为odd[0].size(),显然他是通过j=0来转化得到的但由于是第一个联通块,所以在他之前没有别的连通块,但是因为该点确实存在,所以不能把first定为-1,应该定为0。接下来就是dp的状态转移了。

    第一层for表示第几个连通块,第二次for表示已包含了0~n个结点。dp转移的时候,从当前转移到下一个,判断条件是当前dp[i][j].first是否>=0,并且加上第i+1层的奇数层次数目或者偶数层次数目仍然<=n,如果可以那就能转移

    第二步判断:如果dp[总组数][n2].first>=0,那么说明可以转化到n2。所以只需要通过回溯不断寻找每个节点的答案就行。每一次更新now=他的后继转移过来的,即他的first。组数t每次减少1,直到为0终止转移。判断如果now.second==0,那么说明选择当前连通块中奇数层;反之选择偶数层。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,n) for(int i=a;i<=n;i++)
    #define per(i,n,a) for(int i=n;i>=a;i--)
    #define endl '
    '
    #define pb push_back
    #define mem(a,b) memset(a,b,sizeof(a))
    #define IO ios::sync_with_stdio(false);cin.tie(0);
    using namespace std;
    const int INF=0x3f3f3f3f;
    const ll inf=0x3f3f3f3f3f3f3f3f;
    const int mod=1e9+7;
    const int maxn=1e5+5;
    int tot,head[maxn];
    struct E{
        int to,next;
    }edge[maxn<<1];
    void add(int u,int v){
        edge[tot].to=v;
        edge[tot].next=head[u];
        head[u]=tot++;
    }
    vector<int> vec;
    int a[5],n,m,dfn[5005],tott=0,depth[5005];
    void dfs(int x,int fa){
        vec.push_back(x);
        dfn[x]=++tott;
        depth[x]=depth[fa]+1;
        for(int i=head[x];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(v==fa) continue;
            if(!dfn[v]) dfs(v,x);
            else{
                if((dfn[x]-dfn[v]+1)%2==1){
                    puts("NO");exit(0);
                }
            }
        }
    }
    pair<int,int> dp[5005][5005];
    int ans[5005];
    int main(){
        scanf("%d%d",&n,&m);mem(head,-1);
        rep(i,0,2) cin>>a[i];
        while(m--){
            int u,v;scanf("%d%d",&u,&v);
            add(u,v);add(v,u);
        }
        vector<vector<int> >odd,even;
        int groupnum=0;
        for(int i=1;i<=n;i++){
            if(!dfn[i]){
                vec.clear();
                dfs(i,0);
                vector<int> v1,v2;
                for(auto it:vec){
                    if(depth[it]%2==1) v1.push_back(it);
                    else v2.push_back(it);
                }
                ++groupnum;
                odd.push_back(v1);
                even.push_back(v2);
            }
        }
        int blocks=groupnum;
        mem(dp,-1);
        dp[0][odd[0].size()]={0,0};
        dp[0][even[0].size()]={0,1};
        for(int i=0;i<blocks-1;i++){
            for(int j=0;j<=n;j++){
                if(dp[i][j].first>=0){
                    if(j+odd[i+1].size()<=n)  dp[i+1][j+odd[i+1].size()]={j,0};
                    if(j+even[i+1].size()<=n) dp[i+1][j+even[i+1].size()]={j,1}; 
                }
            }
        }
        if(dp[blocks-1][a[1]].first>=0){
            puts("YES");
            pair<int,int> now=dp[blocks-1][a[1]];
            int t=blocks-1;
            while(t>=0){
                if(now.second==0){
                    for(auto it:odd[t]){
                        ans[it]=2;
                    }
                    for(auto it:even[t]){
                        if(a[0]){ans[it]=1;--a[0];}
                        else{ans[it]=3;}
                    }
                }
                else{
                    for(auto it:even[t]){
                        ans[it]=2;
                    }
                    for(auto it:odd[t]){
                        if(a[0]){ans[it]=1;--a[0];}
                        else{ans[it]=3;}
                    }                
                }
                if(t==0) break;
                --t;
                now=dp[t][now.first];
            }
            rep(i,1,n) cout<<ans[i];
        }else{
            puts("NO");
        }
    }
    View Code
  • 相关阅读:
    JavaScript中getBoundingClientRect()方法详解
    webpack解惑:require的五种用法 (转)
    大白话讲解Promise(一)
    HTML5触摸事件(touchstart、touchmove和touchend) (转)
    JavaScript 数组中的 indexOf 方法
    arguments
    webpack入坑之旅
    webpack-dev-server
    webpackJsonp is not defined?
    CSS3——背景 文本 字体 链接 列表样式 表格
  • 原文地址:https://www.cnblogs.com/Anonytt/p/12913241.html
Copyright © 2020-2023  润新知