• [Codeforces 1239D]Catowise City(2-SAT)


    [Codeforces 1239D]Catowise City(2-SAT)

    题面

    有n个主人,每个主人都有一只猫。每个主人认识一些猫(包括自己的猫)。现在要选出一些人和一些猫,个数均大于0且总共为n,且所有人和所有猫都互不认识。判断是否有解,有解输出任意一组方案.

    (n leq 10^6)

    分析

    如果选择人i参加,那么i认识的猫一定不能参加。那么i认识的猫的主人一定要参加。这样就可以保证少了认识的猫,但是多了认识猫的主人,人数和猫数之和仍为n.

    因此可以这样建图:对于人i认识的每只猫的主人j,由i向j连一条有向边,表示选了i就一定要选j。

    根据2-SAT的套路,选了一个点-双联通分量中的任意一个点,那么这个v-DCC里的所有点都要被选择。

    那么就可以缩点。如果只有一个v-DCC,说明没有猫被选择,不符合题意。

    否则选缩点后的图里任意一个出度为0的v-DCC即可。这里面的全选人,剩下的点全选猫。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<stack> 
    #define maxn 1000000
    using namespace std;
    int t,n,m;
    vector<int>E[maxn*2+5];
    void add_edge(int u,int v){
        E[u].push_back(v);
    }
     
    int dfn[maxn*2+5];
    int low[maxn*2+5];
    stack<int>st;
    int cnt=0,tim=0;
    int bel[maxn*2+5];
    bool ins[maxn*2+5];
    vector<int>bcc[maxn*2+5];
    void tarjan(int x){
        dfn[x]=low[x]=++tim;
        st.push(x);
        ins[x]=1;
        for(int y : E[x]){
            if(!dfn[y]){
                tarjan(y);
                low[x]=min(low[x],low[y]); 
            }else if(ins[y]){
                low[x]=min(low[x],dfn[y]);
            }
        }
        if(low[x]==dfn[x]){
            cnt++;
            int y;
            do{
                y=st.top();
                st.pop();
                ins[y]=0;
                bel[y]=cnt;
                bcc[cnt].push_back(y); 
            }while(y!=x); 
        }
    }
     
    bool is_jury[maxn*2+5];
    void ini(){
    	for(int i=1;i<=n*2;i++){
    		E[i].clear();
    		bcc[i].clear();
    		bel[i]=dfn[i]=low[i]=0;
    		is_jury[i]=0;
    	}
    	cnt=tim=0;
    }
     
     
    int main(){
    	int u,v;
    	scanf("%d",&t);
    	while(t--){
    		scanf("%d %d",&n,&m);
    		ini();
    		for(int i=1;i<=m;i++){
    			scanf("%d %d",&u,&v);
    			if(u==v) continue;
    			E[u].push_back(v);
    		}
    		for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
    		if(cnt==1) printf("No
    ");
    		else{
    			printf("Yes
    ");
    			printf("%d %d
    ",bcc[1].size(),n-bcc[1].size());
    			for(int x : bcc[1]) {
    				is_jury[x]=1;
    				printf("%d ",x); 
    			}
    			printf("
    ");
    			for(int i=1;i<=n;i++){
    				if(!is_jury[i]) printf("%d ",i); 
    			} 
    			printf("
    "); 
    		}
    	}
    }
    
  • 相关阅读:
    uva 1637 Double Patience
    Emacs ^ Vim
    uva 11181 Probability|Given
    uva 10491 Cows and Cars
    uva 1636 Headshot
    hdu 4336 Card Collector
    zoj 3640 Help Me Escape
    Codeforces 148 D Bag of mice
    hdu 4405 Aeroplane chess
    hdu 3853 LOOPS
  • 原文地址:https://www.cnblogs.com/birchtree/p/11727962.html
Copyright © 2020-2023  润新知