• POJ


    题意:有N-1对夫妇和1对新郎新娘要出席婚礼,这N对人要坐在走廊两侧。要求每对夫妇要坐在不同侧。有M对人有通奸关系,对于这一对人,不能同时坐在新娘对面(新娘新郎也可能和别人有通奸关系)。求如何避免冲突安排每对人。
    分析:相当于选择N个坐在新娘对面且不会冲突的人。根据给定的M条关系建图,若a与b有关系,则选a坐对面则必定选b的伴侣坐对面;且选b坐对面则必定选a的伴侣坐对面。最后要加一条(0,1)的有向边(保证新郎一定会被选到另一侧)。
    建图后跑Tarjan,若有一对夫妻处在强连通分量中,则无解;否则强连通缩点后根据关系染色,输出每对夫妻中与新娘同色的人。

    #include<stdio.h>
    #include<iostream>
    #include<cstring>
    #include<stack>
    #include<queue>
    #include<vector>
    using namespace std;
    typedef long long LL;
    const int maxn =1e3+5;
    struct Edge{
        int v,next;  
    }edges[maxn<<2],E[maxn<<2];
    int head[maxn],tot;
    int H[maxn],tt;
    stack<int> S;
    int pre[maxn],low[maxn],sccno[maxn],dfn,scc_cnt,ind[maxn],col[maxn];
    void init()
    {
        tt = tot = dfn = scc_cnt=0;
        memset(H,-1,sizeof(H));
        memset(col,0,sizeof(col));
        memset(pre,0,sizeof(pre));
        memset(sccno,0,sizeof(sccno));
        memset(head,-1,sizeof(head));
        memset(ind,0,sizeof(ind));
    }
    void AddEdge(int u,int v)   {
        edges[tot] = (Edge){v,head[u]};
        head[u] = tot++;
    }
    
    void nAddEdge(int u,int v){
        E[tt] = (Edge){v,H[u]};
        H[u] = tt++;
    }
    
    void Tarjan(int u)
    {
        int v;
        pre[u]=low[u]=++dfn;
        S.push(u);
        for(int i=head[u];~i;i=edges[i].next){
            v= edges[i].v;
            if(!pre[v]){
                Tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else if(!sccno[v]){
                low[u]=min(low[u],pre[v]);
            }
        }
        if(pre[u]==low[u]){
            int x;
            ++scc_cnt;
            for(;;){
                x = S.top();S.pop();
                sccno[x]=scc_cnt;
                if(x==u)break;
            }
        }    
    }
    
    int n,m;
    int bad[maxn];
    void solve()
    {
        int all = 2*n,a,b;
        for(int u = 0;u<all;u+=2){
            a = sccno[u] ,b = sccno[u+1];
            if(a == b){
                printf("bad luck
    ");
                return;
            }
            bad[a] = b;
            bad[b] = a;
        }
        //缩点
        for(int u=0;u<all;u++){
            a = sccno[u];
            for(int i =head[u];~i;i=edges[i].next){
                int v = edges[i].v;
                b = sccno[v];
                if(a!=b){
                    ind[b]++;
                    nAddEdge(a,b);          //逆拓扑排序
                }   
            }
        }
        //拓扑排序染色
        queue<int> Q;
        for(int u=1;u<=scc_cnt;++u){
            if(!ind[u]) Q.push(u);
        }
        while(!Q.empty()){
            int u = Q.front(); Q.pop();
            if(!col[u]){
                col[u] = 1;
                col[bad[u]] = 2;
            }
            for(int i=H[u];~i;i=E[i].next){
                int v= E[i].v;
                ind[v]--;
                if(!ind[v]){
                    Q.push(v);
                }
            }
        }
        for(int i=2;i<all;i+=2){
            if(i!=2) printf(" ");
            if(col[sccno[i]]==col[sccno[0]]) printf("%dw",i/2);
            else printf("%dh",i/2);
        }
        puts("");
    }
    
    int main()
    {
        #ifndef ONLINE_JUDGE
            freopen("in.txt","r",stdin);
            freopen("out.txt","w",stdout);
        #endif
        int u,v,tmp;
        char c1,c2;
        while(scanf("%d %d",&n,&m)==2){
            if(!n &&!m) break;
            init();
            int id1,id2,x1,y1;
            for(int i = 1;i<=m;++i){
                scanf("%d%c %d%c",&id1,&c1,&id2,&c2);
                if(c1=='h') x1 = 2*id1+1;
                else x1 = 2*id1;
                if(c2=='h') y1 = 2*id2+1;
                else  y1 = 2*id2;
                //如果x与y有**关系,则有关系:选x必选y' 且 选y必选x' 
                AddEdge(x1,y1^1);
                AddEdge(y1,x1^1);
            }
            AddEdge(0,1);       //这样如果选了新娘就会判断无解,选出来的组合一定包含新郎
            int all = 2*n;
            for(int i=0;i<all;++i){
                if(!pre[i]){
                    Tarjan(i);
                }
            }
            solve();
        }
        return 0;
    }
    
    为了更好的明天
  • 相关阅读:
    SQL中UNION的使用
    [转]身份证号准确性检测
    shell中if/seq/for/while/until
    shell中数字、字符串、文件比较测试
    shell简介及变量的定义查看撤销
    grep/字符/次数匹配/锚定符/小大括号/wc/tr/cut/sort/uniq
    linux全局和个人配置文件说明
    linux文件的3个时间和7种文件类型
    linux常用配置文件和命令总结
    目录方式扩展swap分区大小
  • 原文地址:https://www.cnblogs.com/xiuwenli/p/9549091.html
Copyright © 2020-2023  润新知