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

1251 - Forming the Council

PDF (English) Statistics 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, N);
        solve();
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-01 05:06:11

Light oj 1251 - Forming the Council 【2-sat】【判断是否存在可行解 + 反向拓扑输出可行解】的相关文章

Light OJ 1251 Forming the Council 2-SAT输出任意一组解

题目来源:Light OJ 1251 Forming the Council 题意:若干了条件至少满足一个 求是否有方案 输出任意一种可能的方案 留下的人的个数 思路:2-SAT基础题 #include <cstdio> #include <cstring> #include <vector> using namespace std; const int maxn = 100010; int n, m; vector <int> G[maxn*2]; boo

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

LightOJ 1251 Forming the Council(2-set入门)

2-set 定义: 有n个布尔变量\(x_i\)和m个形如\(x_i = true/false || x_j = true /false\)的条件,问能否为每个变量赋值使得,m个条件均被满足 解决: 对每个变量\(x_i\),拆成\(2i和2i+1\)两个点分别表示\(x_i\)为\(false/true\),最后对每个变量都设置一个赋值. 对于\(x_i = true || x_j = false\),在\(2i和2j\)建有向边(\(x_i\)为假,则\(x_j\)一定为假),在\(2j+1

Light OJ 1288 Subsets Forming Perfect Squares 高斯消元求矩阵的秩

题目来源:Light OJ 1288 Subsets Forming Perfect Squares 题意:给你n个数 选出一些数 他们的乘积是完全平方数 求有多少种方案 思路:每个数分解因子 每隔数可以选也可以不选 0 1表示 然后设有m种素数因子 选出的数组成的各个因子的数量必须是偶数 组成一个m行和n列的矩阵 每一行代表每一种因子的系数 解出自由元的数量 #include <cstdio> #include <cstring> #include <algorithm&g

light oj 1236 【大数分解】

给定一个大数,分解质因数,每个质因子的个数为e1,e2,e3,--em, 则结果为((1+2*e1)*(1+2*e2)--(1+2*em)+1)/2. //light oj 1236 大数分解素因子 #include <stdio.h> #include <iostream> #include <string.h> #include <algorithm> #include <math.h> #include <ctype.h> #i

[2016-04-21][light]OJ[1234][Harmonic Number]

时间:2016-04-21 22:18:26 星期四 题目编号:[2016-04-21][light]OJ[1234][Harmonic Number] 题目大意:求∑nk=11kn∈(1,108),精确到10?8求∑k=1n1kn∈(1,108),精确到10?8 分析: 想法是打表,然后输出,但是直接打表会爆内存 解决办法,就是每隔100个来打表,节省1100的空间,然后从那个值开始计算到当前值解决办法,就是每隔100个来打表,节省1100的空间,然后从那个值开始计算到当前值 对应的整百就是n

Light OJ 1411 Rip Van Winkle`s Code 线段树成段更新

题目来源:Light OJ 1411 Rip Van Winkle`s Code 题意:3中操作 1种查询 求区间和 其中每次可以把一段区间从左到右加上1,2,3,...或者从右到左加上...3,2,1 或者把某个区间的数都置为v 思路:我是加了6个域 add是这段区间每个数都要加上add  add是这么来的 对与123456...这个等差数列 可能要分为2个区间 那么我就分成123和123 两个右边的等差数列每个数还应该加上3 所以右区间add加3 v是这个区间都要置为v 他的优先级最高 b是

Light OJ 1168 Wishing Snake 强连通缩点+哈密顿通路

题目来源:Light OJ 1168 Wishing Snake 题意:有点难看懂题意 看了一个小时再加别人的代码才懂意思 从0开始 输入的那些每一对u v 都要经过 就是从0到到达那些点 思路:首先缩点 每一个强连通分量里面的点都是可达的 缩点后的图是有向无环图 如果从0这个强连通分量可以出去到2个强连通分量 那么这两个强连通分量是不可能相互可达 所以可行的方案就是所有的强连通分量连成一线 一个一个串起来 除了第一个 出度是1入度是0和最后一个出度是0入度是1 其他都是入度等于出度是1 特判只

Jan&#39;s light oj 01--二分搜索篇

碰到的一般题型:1.准确值二分查找,或者三分查找(类似二次函数的模型). 2.与计算几何相结合答案精度要求比较高的二分查找,有时与圆有关系时需要用到反三角函数利用 角度解题. 3.不好直接求解的一类计数问题,利用二分直接枚举可能的结果,再检查是否符合题目要求. 4.区间求解,即利用两次二分分别查找有序序列左右上下限,再求差算出总个数. 题型知识补充: 1. 三分的一般写法: 1 double thfind(double left,double right) 2 { 3 double midmid