洛谷 P3007 [USACO11JAN]大陆议会The Continental Cowngress【2-SAT】

题目描述

(原英文题面见洛谷)
由于对Farmer John的领导感到极其不悦,奶牛们退出了农场,组建了奶牛议会。

议会以“每头牛 都可以获得自己想要的”为原则,建立了下面的投票系统: M只到场的奶牛 (1 <= M <= 4000) 会给N个议案投票(1 <= N <= 1,000) 。每只 奶牛会对恰好两个议案 B_i and C_i (1 <= B_i <= N; 1 <= C_i <= N)投 出“是”或“否”(输入文件中的’Y’和’N’)。

他们的投票结果分别为VB_i (VB_i in {‘Y’, ‘N’}) and VC_i (VC_i in {‘Y’, ‘N’})。 最后,议案会以如下的方式决定:每只奶牛投出的两票中至少有一票和最终结果相符合。 例如Bessie给议案1投了赞成’Y’,给议案2投了反对’N’,那么在任何合法的议案通过 方案中,必须满足议案1必须是’Y’或者议案2必须是’N’(或者同时满足)。

给出每只奶牛的投票,你的工作是确定哪些议案可以通过,哪些不能。

如果不存在这样一个方案, 输出”IMPOSSIBLE”。

如果至少有一个解,输出: Y 如果在每个解中,这个议案都必须通过 N 如果在每个解中,这个议案都必须驳回 ? 如果有的解这个议案可以通过,有的解中这个议案会被驳回

输入格式:

  • Line 1: Two space-separated integers: N and M
  • Lines 2..M+1: Line i+1 describes cow i’s votes with four

space-separated fields – an integer, a vote, another integer, and another vote: B_i, VB_i, C_i, VC_i

输出格式:

  • Line 1: A string with N characters, where the ith character is either a ‘Y’ if the ith bill must pass, an ‘N’ if the ith bill must fail, or a ‘?’ if it cannot be determined whether the bill passes from these votes.

If there is no solution which satisfies every cow, then output the single line ‘IMPOSSIBLE’.


题目分析

一道比较特殊的2-SAT

2-SAT—详解

限制条件是最基本的形式,就不再讲了

这题的方案输出看起来很麻烦
但其实远比想象的简单

扫描二维码关注公众号,回复: 2800830 查看本文章

tarjan求SCC后缩点
直接枚举每个点(议案)的两种状态
然后从表示该状态的结点(col[i]和col[i+n])出发深搜并标记访问到的点
最后检测是否有 c o l [ i ] c o l [ i + n ] 都被访问到即可

虽然实测不缩点直接深搜也可以过
但理论上的时间复杂度是不对的
可以被特殊数据hack


#include<iostream>
#include<stack>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long lt;

int read()
{
    int f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}

const int maxn=4010;
int n,m;
struct node{int v,nxt;}E[2][maxn<<1];
int head[2][maxn],tot[2];
int low[maxn],dfn[maxn],cnt;
int col[maxn],ins[maxn],colnum;
int st[maxn],top;
int vis[maxn];
char s1[5],s2[5],ans[maxn];

void add(int u,int v,int d)
{
    E[d][++tot[d]].nxt=head[d][u];
    E[d][tot[d]].v=v;
    head[d][u]=tot[d];
}

void dfs(int u)
{
    vis[u]=1;
    for(int i=head[1][u];i;i=E[1][i].nxt)
    if(!vis[E[1][i].v]) dfs(E[1][i].v);
}

void tarjan(int u)
{
    low[u]=dfn[u]=++cnt;
    st[++top]=u; ins[u]=1;
    for(int i=head[0][u];i;i=E[0][i].nxt)
    {
        int v=E[0][i].v;
        if(!dfn[v]){tarjan(v);low[u]=min(low[u],low[v]);}
        else if(ins[v])low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        colnum++;
        do{
            ins[st[top]]=0;
            col[st[top]]=colnum;
        }while(st[top--]!=u);
    }
}

int check(int u)
{
    memset(vis,0,sizeof(vis));
    dfs(u);
    for(int i=1;i<=n;++i)
    if(vis[col[i]]&&vis[col[i+n]])return 0;
    return 1;
}

int main()
{
    n=read();m=read();
    for(int i=1;i<=m;++i)//N-0,Y-1
    {
        int u=read(); scanf("%s",&s1);
        int v=read(); scanf("%s",&s2);
        if(s1[0]=='Y')
        {
            if(s2[0]=='N')add(u,v,0),add(v+n,u+n,0);
            else if(s2[0]=='Y')add(u,v+n,0),add(v,u+n,0);
        }
        else if(s1[0]=='N')
        {
            if(s2[0]=='N')add(u+n,v,0),add(v+n,u,0);
            else if(s2[0]=='Y')add(u+n,v+n,0),add(v,u,0);
        }
    }

    for(int i=1;i<=n<<1;++i)
    if(!dfn[i])tarjan(i);

    for(int u=1;u<=n<<1;++u)
    for(int i=head[0][u];i;i=E[0][i].nxt)
    {
        int v=E[0][i].v;
        if(col[u]==col[v])continue;
        add(col[u],col[v],1);
    }

    for(int i=1;i<=n;++i)
    {
        int p=check(col[i]),q=check(col[i+n]);
        if(!p&&!q){printf("IMPOSSIBLE");return 0;}
        else if(p&&q)ans[i]='?';
        else if(p&&!q)ans[i]='N';
        else if(!p&&q)ans[i]='Y';
    }
    for(int i=1;i<=n;++i)
    cout<<ans[i];
    return 0;
}

猜你喜欢

转载自blog.csdn.net/niiick/article/details/81450249