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("\n");
        }
    }

    return 0;
}

 

posted @ 2017-12-16 10:08  zbtrs  阅读(196)  评论(0编辑  收藏  举报