zoukankan      html  css  js  c++  java
  • poj3648 Wedding

    Wedding
    Time Limit: 1000MS   Memory Limit: 65536K
    Total Submissions: 10975   Accepted: 3355   Special Judge

    Description

    Up to thirty couples will attend a wedding feast, at which they will be seated on either side of a long table. The bride and groom sit at one end, opposite each other, and the bride wears an elaborate headdress that keeps her from seeing people on the same side as her. It is considered bad luck to have a husband and wife seated on the same side of the table. Additionally, there are several pairs of people conducting adulterous relationships (both different-sex and same-sex relationships are possible), and it is bad luck for the bride to see both members of such a pair. Your job is to arrange people at the table so as to avoid any bad luck.

    Input

    The input consists of a number of test cases, followed by a line containing 0 0. Each test case gives n, the number of couples, followed by the number of adulterous pairs, followed by the pairs, in the form "4h 2w" (husband from couple 4, wife from couple 2), or "10w 4w", or "3h 1h". Couples are numbered from 0 to n - 1 with the bride and groom being 0w and 0h.

    Output

    For each case, output a single line containing a list of the people that should be seated on the same side as the bride. If there are several solutions, any one will do. If there is no solution, output a line containing "bad luck".

    Sample Input

    10 6
    3h 7h
    5w 3w
    7h 6w
    8w 3w
    7h 3w
    2w 5h
    0 0
    

    Sample Output

    1h 2h 3w 4h 5h 6h 7h 8h 9h
    

    Source

    分析:2-SAT问题,先搞清楚每个点拆成什么.对于第i对夫妇,i*2表示丈夫坐在新娘这一边,i*2+1表示妻子坐在新娘这一边.这样拆点的话,每对夫妇内部是不需要连边的,因为i*2和i*2+1是互相矛盾的,两个只能取一个.而并不是取了i*2就要取i*2对立的那一个.这是当初令我比较困惑的一个问题.
              主要的就是处理有矛盾的组合了.如果第i对的丈夫坐在了新娘对面,他不能和第j对的妻子坐在同一边,那么它肯定是和第j对的丈夫坐在同一边,以此类推,利用矛盾关系连边.
              最后要输出方案,常用的办法是对缩点后的图反向连边,跑一次拓扑排序,先到达的强连通分量为真,对立的强连通分量为假.
    #include <cstdio>
    #include <stack>
    #include <queue>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 1000010;
    int n, m, head[maxn], to[maxn], id[maxn], nextt[maxn], tot = 1, scc[maxn], pre[maxn], low[maxn], dfs_clock, cnt;
    int head2[maxn], to2[maxn], nextt2[maxn], tot2 = 1, du[maxn], ok[maxn];
    stack <int> s;
    bool flag = true;
    
    void init()
    {
        memset(head, 0, sizeof(head));
        memset(id, 0, sizeof(id));
        tot = 1;
        memset(scc, 0, sizeof(scc));
        memset(pre, 0, sizeof(pre));
        memset(low, 0, sizeof(low));
        dfs_clock = cnt = 0;
        memset(head2, 0, sizeof(head2));
        tot2 = 1;
        memset(ok, 0, sizeof(ok));
        memset(du, 0, sizeof(du));
        flag = true;
    }
    
    void add(int x, int y)
    {
        to[tot] = y;
        nextt[tot] = head[x];
        head[x] = tot++;
    }
    
    void add2(int x, int y)
    {
        to2[tot2] = y;
        nextt2[tot2] = head2[x];
        head2[x] = tot2++;
    }
    
    void tarjan(int u)
    {
        s.push(u);
        pre[u] = low[u] = ++dfs_clock;
        for (int i = head[u]; i; i = nextt[i])
        {
            int v = to[i];
            if (!pre[v])
            {
                tarjan(v);
                low[u] = min(low[u], low[v]);
            }
            else
                if (!scc[v])
                    low[u] = min(low[u], pre[v]);
        }
        if (low[u] == pre[u])
        {
            cnt++;
            while (1)
            {
                int t = s.top();
                s.pop();
                scc[t] = cnt;
                if (t == u)
                    break;
            }
        }
    }
    
    void topo()
    {
        queue <int> q;
        for (int i = 1; i <= cnt; i++)
            if (!du[i])
                q.push(i);
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            if (!ok[u])
            {
                ok[u] = 1;
                ok[id[u]] = 2;
                for (int i = head2[u]; i; i = nextt2[i])
                {
                    int v = to2[i];
                    if ((--du[v]) == 0)
                        q.push(v);
                }
            }
        }
    }
    
    int main()
    {
        while (scanf("%d%d", &n, &m) == 2 && (n || m))
        {
            init();
            for (int i = 1; i <= m; i++)
            {
                int a, b;
                char c, d;
                scanf("%d%c %d%c", &a, &c, &b, &d);
                add(c == 'h' ? a * 2 + 1 : a * 2, d == 'h' ? b * 2 : b * 2 + 1);
                add(d == 'h' ? b * 2 + 1 : b * 2, c == 'h' ? a * 2 : a * 2 + 1);
            }
            add(0, 1);
            for (int i = 0; i < n * 2; i++)
                if (!pre[i])
                    tarjan(i);
            for (int i = 0; i < n; i++)
            {
                if (scc[i * 2] == scc[i * 2 + 1])
                {
                    flag = false;
                    break;
                }
                id[scc[i * 2]] = scc[i * 2 + 1];
                id[scc[i * 2 + 1]] = scc[i * 2];
            }
            if (!flag)
                puts("bad luck");
            else
            {
                for (int i = 0; i < 2 * n; i++)
                {
                    for (int j = head[i]; j; j = nextt[j])
                    {
                        int v = to[j];
                        if (scc[v] != scc[i])
                        {
                            add2(scc[v], scc[i]);
                            du[scc[i]]++;
                        }
                    }
                }
                topo();
                for (int i = 1; i < n; i++)
                {
                    if (ok[scc[i * 2]] == 1)
                        printf("%dh ", i);
                    else
                        printf("%dw ", i);
                }
                printf("
    ");
            }
        }
    
        return 0;
    }
  • 相关阅读:
    题解 P2647 【最大收益】
    CF817E Choosing The Commander
    P2922 [USACO08DEC]Secret Message G
    洛谷月赛 P7107 天选之人
    如何在考场上快速用C++写高级对拍器
    题解 CF527D 【Clique Problem】
    P6768 [USACO05MAR]Ombrophobic Bovines 发抖的牛
    [USACO06NOV]Corn Fields G
    Orz 教主的比赛题解
    JZOI 4311 统一天下
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8045921.html
Copyright © 2011-2022 走看看