POJ 3648 Wedding (2-SAT+输出可行解)

题目地址:POJ 3648

这题终于AC了。。。。没有专门对新郎新娘加一条边。。

这题前面一直读错题意了,调试了好长时间样例也没过。。这题的意思是只要新郎那一边没有通奸的就可以,然后输出新娘那一边的人。

然后就是对那些有**关系的加边,由于新郎新娘必须要在两侧,所以最后要额外加一条边。然后用强连通判断,逆拓扑染色输出可行解即可。

代码如下:

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <queue>
#include <map>
#include <set>
#include <algorithm>

using namespace std;
#define LL __int64
const int INF=0x3f3f3f3f;
int head[2001], cnt, ans, top, index;
int dfn[2100], low[2100], belong[2100], instack[2100], stak[2100];
struct node
{
    int u, v, next;
}edge[1000000];
void add(int u, int v)
{
    edge[cnt].v=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
void tarjan(int u)
{
    dfn[u]=low[u]=++index;
    instack[u]=1;
    stak[++top]=u;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(instack[v])
        {
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(dfn[u]==low[u])
    {
        ans++;
        while(1)
        {
            int v=stak[top--];
            instack[v]=0;
            belong[v]=ans;
            if(u==v) break;
        }
    }
}
int head1[2100], cnt1, in[2100], ct[2100], color[2100], c[2100], tot;
struct N
{
    int u, v, next;
}edge1[1000000];
void add1(int u, int v)
{
    edge1[cnt1].v=v;
    edge1[cnt1].next=head1[u];
    head1[u]=cnt1++;
}
void topo(int n)
{
    int i;
    queue<int>q;
    for(i=1;i<=ans;i++)
    {
        if(!in[i])
            q.push(i);
    }
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        if(!color[u])
        {
            color[u]=1;
            color[ct[u]]=-1;
        }
        for(i=head1[u];i!=-1;i=edge1[i].next)
        {
            int v=edge1[i].v;
            in[v]--;
            if(!in[v])
                q.push(v);
        }
    }
}
void init()
{
    memset(head,-1,sizeof(head));
    cnt=ans=top=index=0;
    memset(dfn,0,sizeof(dfn));
    memset(instack,0,sizeof(instack));
    memset(head1,-1,sizeof(head1));
    cnt1=0;
    memset(in,0,sizeof(in));
    memset(color,0,sizeof(color));
}
int main()
{
    int n, m, i, j, len1, len2, x, y;
    char s1[10], s2[10];
    while(scanf("%d%d",&n,&m)!=EOF&&n+m)
    {
        init();
        while(m--)
        {
            scanf("%s%s",s1,s2);
            len1=strlen(s1);
            len2=strlen(s2);
            x=y=0;
            for(i=0;i<len1-1;i++)
                x=x*10+s1[i]-'0';
            for(i=0;i<len2-1;i++)
                y=y*10+s2[i]-'0';
            x<<=1;
            y<<=1;
            if(s1[len1-1]=='w')
                x++;
            if(s2[len2-1]=='w')
                y++;
                //printf("%d %d\n",x,y);
            add(x,y^1);
            add(y,x^1);
        }
        add(1,0);
        for(i=0;i<n<<1;i++)
        {
            if(!dfn[i])
                tarjan(i);
        }
        int flag=0;
        for(i=0;i<n;i++)
        {
            if(belong[i<<1]==belong[i<<1|1])
            {
                flag=1;
                break;
            }
            ct[belong[i<<1]]=belong[i<<1|1];
            ct[belong[i<<1|1]]=belong[i<<1];
        }
        if(flag)
            puts("bad luck");
        else
        {
            for(i=0;i<n<<1;i++)
            {
                for(j=head[i];j!=-1;j=edge[j].next)
                {
                    int v=edge[j].v;
                    if(belong[i]!=belong[v])
                    {
                        add1(belong[v],belong[i]);
                        in[belong[i]]++;
                    }
                }
            }
            topo(n);
            tot=0;
            for(i=2;i<n<<1;i++)
            {
                if(color[belong[i]]==-1)
                {
                    c[tot++]=i;
                }
            }
            for(i=0;i<tot;i++)
            {
                if(c[i]&1)
                    printf("%dw",c[i]/2);
                else
                    printf("%dh",c[i]/2);
                    if(i!=tot-1)
                        printf(" ");
            }
            puts("");
            /*for(i=0;i<n<<1;i++)
            {
                printf("%d ",color[belong[i]]);
            }
            puts("");*/
        }
    }
    return 0;
}

时间: 2024-08-10 12:20:10

POJ 3648 Wedding (2-SAT+输出可行解)的相关文章

POJ 3648 Wedding(2-SAT 拓扑排序输出任意一种解决方案)

题目链接:http://poj.org/problem?id=3648 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 h

poj 3648 Wedding 2-SAT问题入门题目

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

poj 3648 Wedding

每对夫妻恰有一人坐在新娘对面,两个关系不正常的人不能都在新娘对面 问,是否有解 #include<iostream> #include<map> #include<string> #include<cstring> #include<cstdio> #include<cstdlib> #include<cmath> #include<queue> #include<vector> #include&

UVA 11294 POJ 3648 Wedding

题意: 婚礼上新郎新娘坐在桌子两侧  新娘只能看见对面的人  已知一些人有XX关系-  新娘不想看见有关系的同时坐在对面  问  满足条件的情况下  新娘这边做的人是谁 思路: 新郎那一边的约束最多  有利于解题  那么就变成了  一个人要不要坐新郎这边的2-sat问题  因此可以先求新郎这边的人  然后反一下就是新娘这边的了  注意  新郎是必选点  而且  不能选和新郎有XX关系的- 代码: #include<cstdio> #include<cstring> #include

POJ 3683 Priest John&#39;s Busiest Day (2-SAT+输出可行解)

题目地址:POJ 3683 第一次做需要输出可行解的题目...大体思路是先用强连通来判断是否有可行解,然后用逆序建图,用拓扑排序来进行染色,然后输出可行解.具体思路见传送门 因为判断的时候少写了一个等号..检查了好长时间..sad... 代码如下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #incl

poj 2367 Genealogical tree【拓扑排序输出可行解】

Genealogical tree Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3674   Accepted: 2445   Special Judge Description The system of Martians' blood relations is confusing enough. Actually, Martians bud when they want and where they want. T

poj 2337 之 有向图 欧拉路径输出

/* poj 2337 之 有向图 欧拉路径输出  每个单词看作一条有向边,顶点即为单词首尾字母,然后求欧拉路径即可. 1)为保证字典序,先对单词按字典序排序 2)深搜,输出单词序列 */ 1 #include <iostream> 2 #include <fstream> 3 #include <sstream> 4 #include <cstdlib> 5 #include <cstdio> 6 #include <cstddef>

poj 1815 Friendship 最小割输出最小方案

这题卡了好久啊,最小割模型很容易想,拆点就行.就像poj的Thieves一样 每个点 a拆成 a->a',容量为1. 其他相连的点 a'->b ,容量为INF 源连接s',t连接汇 问题在于输出最小的割集 更好的方法我还不会,只能枚举. 这里基于贪心的思想,从小到大删边, 若删除i->i',会使得最小割变小,则输出i,并且i->i'这条边不要恢复 若最小割不变,则恢复这条边,继续枚举. 一开始就是因为恢复了要割去的边,无限WA. #include<cstdio> #in

Light oj 1251 - Forming the Council 【2-sat】【推断是否存在可行解 + 反向拓扑输出可行解】

1251 - Forming the Council problem=1251" style="color:rgb(79,107,114)"> PDF (English) problem=1251" style="color:rgb(79,107,114)">Statistics problem=1251" style="color:rgb(79,107,114)">Forum Time Limit