1. 程式人生 > >Light oj 1251 - Forming the Council 【2-sat】【推斷是否存在可行解 + 反向拓撲輸出可行解】

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

不存在 type init als -- 代碼 Language all wan

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: 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



題意:一個城市的理事會有M個投票人和N個公民組成,當中公民編號從1——N。

如今要建立一個新的理事會, 每一個投票人都給出了自己的意見,如 1,+i +j 表示 i公民 和 j公民 至少有一個留在理事會 2,+i -j 表示 i公民留在理事會 和 j公民離開理事會 至少有一個成立 3。-i +j 表示 i公民離開理事會 和 j公民留在理事會 至少有一個成立 4,-i -j 表示 i公民 和 j公民 至少有一個離開理事會
如今讓你找出一種方案選取若幹個公民留在理事會。
若不存在方案輸出No。

存在輸出Yes,在下一行輸出選擇的公民總數 並輸出被選擇公民的編號。

思路:2-sat 推斷可行解 + 反向拓撲染色輸出可行解。不是非常難的題目,沒什麽好說的。這裏僅僅說下建圖。

建圖:用 i 表示 i 留在理事會,i + N表示 i 離開理事會。


1。+i +j 表示 i公民 和 j公民 至少有一個留在理事會 addEdge(j + N, i);// j 離開 那麽 i 必然留下
addEdge(i + N, j);// i 離開 那麽 j 必然留下

2。+i -j 表示 i公民留在理事會 和 j公民離開理事會 至少有一個成立 addEdge(j, i);// j 留下 i 必然留下
addEdge(i + N, j + N);// i 離開 j 必然離開

3,-i +j 表示 i公民離開理事會 和 j公民留在理事會 至少有一個成立 addEdge(j + N, i + N);// j 離開 i 必然離開
addEdge(i, j);// i 留下 j 必然留下

4。-i -j 表示 i公民 和 j公民 至少有一個離開理事會 addEdge(j, i + N);// j 留下 那麽 i 必然離開
addEdge(i, j + N);// i 留下 那麽 j 必然離開





AC代碼:

#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
#define MAXN 16000+10
#define MAXM 40000+10
using namespace std;
struct Edge
{
    int from, to, next;
};
Edge edge[MAXM];
int head[MAXN], edgenum;
int low[MAXN], dfn[MAXN];
int sccno[MAXN], scc_cnt;
int dfs_clock;
stack<int> S;
bool Instack[MAXN];
int N, M;
void init()
{
    edgenum = 0;
    memset(head, -1, sizeof(head));
}
void addEdge(int u, int v)
{
    Edge E = {u, v, head[u]};
    edge[edgenum] = E;
    head[u] = edgenum++;
}
void getMap()
{
    int a, b;
    while(M--)
    {
        scanf("%d%d", &a, &b);
        if(a > 0 && b > 0)//a 和 b 至少一個留下
        {
            addEdge(b + N, a);
            addEdge(a + N, b);
        }
        else if(a > 0 && b < 0)//a留 和 b走 至少成立一個
        {
            b = -b;
            addEdge(b, a);
            addEdge(a + N, b + N);
        }
        else if(a < 0 && b > 0)//a走 和 b留 至少成立一個
        {
            a = -a;
            addEdge(b + N, a + N);
            addEdge(a, b);
        }
        else//a 和 b 至少走一個
        {
            a = -a, b = -b;
            addEdge(b, a + N);
            addEdge(a, b + N);
        }
    }
}
void tarjan(int u, int fa)
{
    int v;
    low[u] = dfn[u] = ++dfs_clock;
    S.push(u);
    Instack[u] = true;
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        v = edge[i].to;
        if(!dfn[v])
        {
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
        }
        else if(Instack[v])
            low[u] = min(low[u], dfn[v]);
    }
    if(low[u] == dfn[u])
    {
        scc_cnt++;
        for(;;)
        {
            v = S.top();S.pop();
            Instack[v] = false;
            sccno[v] = scc_cnt;
            if(v == u) break;
        }
    }
}
void find_cut(int l, int r)
{
    memset(low, 0, sizeof(low));
    memset(dfn, 0, sizeof(dfn));
    memset(sccno, 0, sizeof(sccno));
    memset(Instack, false, sizeof(Instack));
    dfs_clock = scc_cnt = 0;
    for(int i = l; i <= r; i++)
        if(!dfn[i]) tarjan(i, -1);
}
vector<int> G[MAXN];
int in[MAXN];
void suodian()//反向建圖
{
    for(int i = 1; i <= scc_cnt; i++) G[i].clear(), in[i] = 0;
    for(int i = 0; i < edgenum; i++)
    {
        int u = sccno[edge[i].from];
        int v = sccno[edge[i].to];
        if(u != v)
            G[v].push_back(u), in[u]++;
    }
}
int k = 1;
int fp[MAXN];//建立SCC到SCC的映射
int color[MAXN];//染色
void toposort()
{
    memset(color, -1, sizeof(color));
    queue<int> Q;
    for(int i = 1; i <= scc_cnt; i++) if(in[i] == 0) Q.push(i);
    while(!Q.empty())
    {
        int u = Q.front();
        Q.pop();
        if(color[u] == -1)
        {
            color[u] = 1;
            color[fp[u]] = 0;
        }
        for(int i = 0; i < G[u].size(); i++)
        {
            int v = G[u][i];
            if(--in[v] == 0)
                Q.push(v);
        }
    }
}
void solve()
{
    printf("Case %d: ", k++);
    for(int i = 1; i <= N; i++)
    {
        if(sccno[i] == sccno[i+N])
        {
            printf("No\n");
            return ;
        }
        else
        {
            fp[sccno[i]] = sccno[i+N];
            fp[sccno[i+N]] = sccno[i];
        }
    }
    printf("Yes\n");
    suodian();
    toposort();//反向拓撲
    int ans = 0;
    for(int i = 1; i <= N; i++)
    {
        if(color[sccno[i]] == 1)
           ans++;
    }
    printf("%d", ans);
    for(int i = 1; i <= N; i++)
    {
        if(color[sccno[i]] == 1)
            printf(" %d", i);
    }
    printf("\n");
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d", &M, &N);
        init();
        getMap();
        find_cut(1, 2*N);
        solve();
    }
    return 0;
}



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