zoukankan      html  css  js  c++  java
  • poj 3648 Wedding 夜

    http://poj.org/problem?id=3648

    新娘和新郎   和其他夫妇 一共n对 每对夫妇不能做在同一侧  而且有奸情的人两个人(男女 男男 女女 出题人口味好重呀)不能同时坐在新娘的对面

    2-SAT  

    限制条件 n对夫妇一共2×n个人 0--n-1 是新娘  n--2×n-1是对应新郎  染色时 1代表和新娘同侧 -1代表不同侧

    首先 新娘必须和新娘同侧2×n-->0 新郎必须和新娘对面n-->n+2×n  

    其他夫妇必须异侧

    有奸情的有一个在新娘对面 另一个一定和新娘同侧

    代码及其注释:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<string>
    #include<vector>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #define LL long long
    
    using namespace std;
    
    const int N=150;
    int head1[N],I1;
    int head2[N],I2;
    struct ss
    {
        int j,next;
    }side1[N*N],side2[N*N];
    int low[N],dfn[N],f[N],deep;
    bool in[N],visited[N];
    int num[N],sele[N];
    stack<int>st;
    queue<int>qt;
    vector<int>vt[N];
    void build1(int x,int y)
    {
        side1[I1].j=y;
        side1[I1].next=head1[x];
        head1[x]=I1++;
    }
    void build2(int x,int y)
    {
        side2[I2].j=y;
        side2[I2].next=head2[x];
        head2[x]=I2++;
    }
    void Tarjan(int x)//将环缩点
    {
        visited[x]=true;
        in[x]=true;
        st.push(x);
        low[x]=dfn[x]=deep++;
        for(int t=head1[x];t!=-1;t=side1[t].next)
        {
            int k=side1[t].j;
            if(visited[k]==false)
            {
                Tarjan(k);
                low[x]=min(low[x],low[k]);
            }else if(in[k]==true)
            {
                low[x]=min(low[x],dfn[k]);
            }
        }
        if(low[x]==dfn[x])
        {
            while(st.top()!=x)
            {
                int k=st.top();
                st.pop();
                in[k]=false;
                f[k]=x;
                vt[x].push_back(k);
            }
            int k=st.top();
            st.pop();
            in[k]=false;
            f[k]=x;
        }
    }
    void Fsearch(int x)//建立新图
    {
        for(int t=head1[x];t!=-1;t=side1[t].next)
        {
            int k=side1[t].j;
            if(f[x]!=f[k])
            {
                build2(f[k],f[x]);
                ++num[f[x]];
            }
        }
    }
    void color(int x,int K)//染色 本环和相对的环 染不同色
    {
        x=f[x];
        sele[x]=1;
        for(unsigned int i=0;i<vt[x].size();++i)
        {sele[vt[x][i]]=1;}
        x=(x<K)?x+K:x-K;
        x=f[x];
        sele[x]=-1;
        for(unsigned int i=0;i<vt[x].size();++i)
        {sele[vt[x][i]]=-1;}
    }
    void subnum(int x)//拓扑 减边
    {
        for(int t=head2[x];t!=-1;t=side2[t].next)
        {
            int k=side2[t].j;
            --num[f[k]];
            if(num[f[k]]==0)
            qt.push(f[k]);
        }
    }
    int main()
    {
        //freopen("data.txt","r",stdin);
        int n,m;
        while(scanf("%d %d",&n,&m)!=EOF)
        {
            if(n==0&&m==0)
            break;
            memset(head1,-1,sizeof(head1));
            I1=0;
            build1(0+2*n,0);//新娘和自己同侧
            build1(n,n+2*n);//新郎对面
            for(int i=1;i<n;++i)
            {
                build1(i,i+n+2*n);//其他夫妇 不能同侧
                build1(i+n,i+2*n);
                build1(i+2*n,i+n);
                build1(i+n+2*n,i);
            }
            for(int i=0;i<m;++i)
            {
                int k1,k2;
                char c1,c2;
                scanf("%d%c%d%c",&k1,&c1,&k2,&c2);
                if(c1=='h')
                k1+=n;
                if(c2=='h')
                k2+=n;
                build1(k1+2*n,k2);//有一个在新娘对面 另一个一定在新娘同侧
                build1(k2+2*n,k1);
            }
            while(!st.empty())
            st.pop();
            for(int i=0;i<4*n;++i)
            {vt[i].clear();f[i]=i;}
            memset(in,false,sizeof(in));
            memset(visited,false,sizeof(visited));
            deep=0;
            int l;
            for(l=0;l<4*n;++l)
            {
                if(visited[l]==false)
                Tarjan(l);
                if(l<2*n&&f[l]==f[l+2*n])
                break;
            }
            if(l<2*n)
            printf("bad luck\n");
            else
            {
                memset(head2,-1,sizeof(head2));
                memset(num,0,sizeof(num));
                I2=0;
                for(int i=0;i<4*n;++i)//将缩点 建新边
                Fsearch(i);
                for(int i=0;i<4*n;++i)
                if(f[i]==i&&num[i]==0)//拓扑中 为0的入队列
                qt.push(i);
                memset(sele,0,sizeof(sele));
                while(!qt.empty())
                {
                    int k=qt.front();
                    qt.pop();
                    if(sele[k]==0)//染色
                    color(k,2*n);
                    subnum(k);
                }
                for(int i=1;i<n;++i)
                {
                    if(sele[i]==1)
                    printf("%dw",i);
                    else
                    printf("%dh",i);
                    if(i<n-1)
                    printf(" ");
                    else
                    printf("\n");
                }
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    Linux 基础篇(二)
    Linux 基础篇
    pandas 的使用
    git 使用和一些错误
    NetBackup :Unable to retrieve version of the server xxx.xxx.xxx
    Splunk 基本使用
    Symantec(赛门铁克)非受管检测
    matplotlib 的几种柱状图
    python 清空list的几种方法
    ACE
  • 原文地址:https://www.cnblogs.com/liulangye/p/2643394.html
Copyright © 2011-2022 走看看