1. 程式人生 > >gym101968 J. Restricted Vertex Cover

gym101968 J. Restricted Vertex Cover

先二分圖染色,求出標號為1的邊的聯通塊個數。然後分兩種況討論,1是聯通塊內的情況,2是聯通塊之間的情況。

第一種情況很簡單,可以直接判斷該聯通塊是選0這種顏色還是1這種顏色。第二種情況用two-sat就好了。

#include<bits/stdc++.h>
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define pb push_back
using namespace std;
const int MX = 4e5+7;
vector<int> G1[MX],G0[MX];
int col[MX],blo[MX],cb[MX];

bool dfs(int u, int fa, int c, int cnt)
{
    col[u] = c;
    blo[u] = cnt;
    for(int v : G1[u]){
        if(col[v] == -1){
            bool flag = dfs(v,u,c^1,cnt);
            if(!flag) return 0;
        }
        else if(col[v] != c^1) return 0;
    }
    return 1;
}

struct TwoSAT{
    int n;
    vector<int> G[MX*2];
    bool mark[MX*2],vis[MX*2];
    int s[MX*2], c;

    bool dfs(int x){
        if(mark[x^1] || vis[x^1]) return 0;
        if(mark[x]) return 1;
        mark[x] = 1;
        s[c++] = x;
        for(int i = 0; i < G[x].size(); i++)
            if(!dfs(G[x][i])) return 0;
        return 1;
    }

    void init(int n){
        this->n = n;
        for(int i = 0; i < n*2; i++) G[i].clear(), mark[i] = vis[i] = 0;
    }

    void add_clause(int x, int xval, int y, int yval){
        x = x*2+xval;
        y = y*2+yval;
        G[x^1].pb(y);
        G[y^1].pb(x);
    }

    bool solve()
    {
        for(int i = 0; i < n*2; i += 2){
            if(!mark[i] && !mark[i+1]){
                c = 0;
                if(!dfs(i)){
                    while(c > 0) mark[s[--c]] = 0;
                    if(!dfs(i+1)) return 0;
                }
            }
        }
        return 1;
    }
}solver;

bool test(int cnt, int n)
{
    solver.init(cnt);
    for(int i = 0; i < cnt; i++)
        if(cb[i] != -1) solver.vis[2*i+cb[i]] = 1;
    for(int u = 1; u <= n; u++){
        for(int v : G0[u]) if(blo[v] != blo[u]){
            int i = blo[v], j = blo[u], ci = col[v], cj = col[u];
            solver.add_clause(i,ci,j,cj);
        }
    }
    return solver.solve();
}

int main()
{
#ifdef LOCAL
    freopen("input.txt","r",stdin);
#endif // LOCAL
    int T;
    scanf("%d",&T);
    while(T--){
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i = 0; i <= n; i++) G0[i].clear(), G1[i].clear(), col[i] = cb[i] = -1;

        for(int i = 1; i <= m; i++){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            if(w == 0) {
                G0[u].pb(v);
                G0[v].pb(u);
                continue;
            }
            G1[u].pb(v);
            G1[v].pb(u);
        }
        bool flag = 1;
        int cnt = 0;
        for(int i = 1; i <= n; i++) if(col[i] == -1){
            flag &= dfs(i,0,0,cnt);
            ++cnt;
        }

        for(int u = 1; u <= n; u++){
            for(int v : G0[u]) if(blo[v] == blo[u]){
                if(col[v] != col[u]) continue;
                int b = blo[v];
                if(cb[b] == -1){
                    cb[b] = col[v];
                }
                else{
                    flag &= (cb[b]==col[v]);
                }
            }
        }
        flag &= test(cnt,n);
        if(flag) puts("YES");
        else puts("NO");
    }
    return 0;
}