LightOJ 1251 Forming the Council【2-Sat+逆向拓扑排序输出可行解】好题!

来源:互联网 发布:seo常用术语 编辑:程序博客网 时间:2024/05/17 07:36

1251 - Forming the Council
   PDF (English)StatisticsForum
Time Limit: 2 second(s)Memory Limit: 32 MB

In a city there are n voters, and m people formed the Govt. council. The council members are numbered from 1 to m. Now everyone is complaining that the council is biased. So, they made a plan. The plan is that the voters are given a chance to vote again to form the new council. A vote will be like ±i ±j. '+' means the voter wants that member to be in the council, '-' means the voter doesn't want the member to be in the council. For example, there are 4 voters, they voted like

+1 -3    the voter wants member 1 to be kept in the council or member 3 to be thrown out

+2 +3  the voter wants member 2 to be kept in the council or member 3 to be kept in the council

-1 -2     the voter wants member 1 to be thrown out or member 2 to be thrown out

-4 +1    the voter wants member 4 to be thrown out or member 1 to be kept in the council

A voter will be satisfied if at least one of his wishes becomes true. Now your task is to form the council such that all the voters are happy.

Input

Input starts with an integer T (≤ 20), denoting the number of test cases.

Each case starts with a line containing two integers n (1 ≤ n ≤ 20000) and m (1 ≤ m ≤ 8000). Each of the next n lines contains a vote in the form ±i ±j (1 ≤ i, j ≤ m).

Output

For each case, print the case number and 'Yes' if a solution exists, or 'No' if there is no solution. Then if the result is yes, print another line containing the number of members in the council followed by the members in ascending order. And print a single space between two numbers. There can be many solutions. Any valid one will do.

Sample Input

Output for Sample Input

3

4 3

+1 +3

+2 -1

+2 -3

-1 -2

4 2

+1 -2

+1 +2

-1 -2

-1 +2

1 3

+1 -3

Case 1: Yes

2 2 3

Case 2: No

Case 3: Yes

0

Note

This is a special judge problem. Wrong output format may cause wrong answer.


PROBLEM SETTER: JANE ALAM JAN

题目大意:

一共有N个选民,M个参选者,一个选民有两个意向,对于+ 表示希望这个人当选。 - 表示希望这个人落选,至少满足一条的结果,对于这个选民来讲就是满足的。

问是否有一个可行解,使得所有选民都满足。

如果有,输出当选的人的编号。


思路:


1、很明显的2-Sat问题。首先我们将一个参选者的当选和不当选进行拆点。

i代表第i个人当选了,i+n代表这个人没有当选。

那么这个问题就变成了一个经典的2-Sat问题。


2、2-Sat问题在于找寻矛盾边,只要矛盾边找寻对了,那么2-Sat的模型和图就建好了。

很明显,对于一个选民来讲,如果两条条件都没有满足,那么很明显这就是矛盾边。

那么对于各种情况,我们建边:



3、接下来跑Tarjan强连通,对应判断是否存在可行解。

对于存在可行解的情况,我们对于缩点之后的图进行反向建图。

然后拓扑排序。

将对立事件进行染色即可。

统计答案进行输出。


Ac代码:


#include<stdio.h>#include<string.h>#include<vector>#include<queue>using namespace std;int output[40005];int vis[70005];int low[70005];int dfn[70005];int print[70005];int stack[70005];int color[70005];int pos[70005];int degree[70005];vector<int >mp[70005];vector<int >mp2[70005];int n,m,sig,cnt,tot,cont;void add(int x,int y){    mp[x].push_back(y);}void top(){    memset(print,0,sizeof(print));    queue<int >s;    for(int i=1;i<=sig;i++)    {        if(degree[i]==0)        {            s.push(i);        }    }    while(!s.empty())    {        int u=s.front();        if(print[u]==0)        {            print[u]=1;print[pos[u]]=2;        }        s.pop();        for(int i=0;i<mp2[u].size();i++)        {            int v=mp2[u][i];            degree[v]--;            if(degree[v]==0)s.push(v);        }    }    cont=0;    for(int i=1;i<=n;i++)if(print[color[i]]==1)output[cont++]=i;}void Tarjan(int u){    vis[u]=1;    dfn[u]=low[u]=cnt++;    stack[++tot]=u;    for(int i=0;i<mp[u].size();i++)    {        int v=mp[u][i];        if(vis[v]==0)Tarjan(v);        if(vis[v]==1)low[u]=min(low[u],low[v]);    }    if(low[u]==dfn[u])    {        sig++;        do        {            vis[stack[tot]]=-1;            color[stack[tot]]=sig;        }        while(stack[tot--]!=u);    }}int Slove(){    sig=0;    cnt=1;    tot=-1;    memset(degree,0,sizeof(degree));    memset(stack,0,sizeof(stack));    memset(dfn,0,sizeof(dfn));    memset(low,0,sizeof(low));    memset(vis,0,sizeof(vis));    memset(color,0,sizeof(color));    for(int i=1;i<=n*2;i++)    {        if(vis[i]==0)        {            Tarjan(i);        }    }    for(int i=1;i<=n;i++)    {        if(color[i]==color[i+n])return 0;        pos[color[i]]=color[i+n];        pos[color[i+n]]=color[i];    }    for(int i=1;i<=n*2;i++)    {        for(int j=0;j<mp[i].size();j++)        {            int v=mp[i][j];            if(color[i]!=color[v])            {                degree[color[i]]++;                mp2[color[v]].push_back(color[i]);            }        }    }    top();    return 1;}int main(){    int t;    int kase=0;    scanf("%d",&t);    while(t--)    {        scanf("%d%d",&m,&n);        for(int i=1;i<=60000;i++)mp[i].clear(),mp2[i].clear();        for(int i=0;i<m;i++)        {            int x,y;            scanf("%d%d",&x,&y);            int xx=x;int yy=y;            if(x<0)x=-x;            if(y<0)y=-y;            if(xx>0&&yy>0)add(x+n,y),add(y+n,x);            if(xx>0&&yy<0)add(x+n,y+n),add(y,x);            if(xx<0&&yy>0)add(x,y),add(y+n,x+n);            if(xx<0&&yy<0)add(x,y+n),add(y,x+n);        }        int ans=Slove();        printf("Case %d: ",++kase);        if(ans==1)        {            printf("Yes\n");            printf("%d",cont);            for(int i=0;i<cont;i++)            {                printf(" %d",output[i]);            }            printf("\n");        }        else printf("No\n");    }}








0 0
原创粉丝点击