hdu1814 2-SAT 暴力搜

Peaceful Commission

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2853    Accepted Submission(s): 901

Problem Description

The Public Peace Commission should be legislated in Parliament of The Democratic Republic of Byteland according to The Very Important Law. Unfortunately one of the obstacles is the fact that some deputies do not get on with some others.

The Commission has to fulfill the following conditions: 
1.Each party has exactly one representative in the Commission, 
2.If two deputies do not like each other, they cannot both belong to the Commission.

Each party has exactly two deputies in the Parliament. All of them are numbered from 1 to 2n. Deputies with numbers 2i-1 and 2i belong to the i-th party .

Task 
Write a program, which: 
1.reads from the text file SPO.IN the number of parties and the pairs of deputies that are not on friendly terms, 
2.decides whether it is possible to establish the Commission, and if so, proposes the list of members, 
3.writes the result in the text file SPO.OUT.

Input

In the first line of the text file SPO.IN there are two non-negative integers n and m. They denote respectively: the number of parties, 1 <= n <= 8000, and the number of pairs of deputies, who do not like each other, 0 <= m <=2 0000. In each of the following m lines there is written one pair of integers a and b, 1 <= a < b <= 2n, separated by a single space. It means that the deputies a and b do not like each other. 
There are multiple test cases. Process to end of file.

Output

The text file SPO.OUT should contain one word NIE (means NO in Polish), if the setting up of the Commission is impossible. In case when setting up of the Commission is possible the file SPO.OUT should contain n integers from the interval from 1 to 2n, written in the ascending order, indicating numbers of deputies who can form the Commission. Each of these numbers should be written in a separate line. If the Commission can be formed in various ways, your program may write mininum number sequence.

Sample Input

3 2
1 3
2 4

Sample Output

1
4
5


第一道2-sat的题目,看了刘汝佳的算法竞赛p324,说的很详细了,比如(2*i-1) hate (2*j) ,选择(2*i-1)必然要选择(2*j-1),建立一条(2*i-1) -> (2*j-1)的边,同理,也可以得出(2*j)->(2*i),把这两条有向边称为对称边

很容易得出,所有的关系都能推导出两条对称边

还有一种情况就是,有些既可以选择2*k-1,也可以选择2*k,这时候,只要讨论2*k-1被选择时,能否得到结果,如果不能,必然要选择2*k

深搜过程中,将所有节点染为白色,认为初始都没有被选择,当k被选择时,k被染为红色,(k^1)被染为蓝色,表示该节点在该次选择的过程中都不能选择了,如果出现深搜了蓝色节点,说明已经发生矛盾了,节点的选择有问题

暴力深搜的复杂度为O(n*m)

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <string>
#include <stack>
#include <vector>
#include <algorithm>
struct edge{
    int st;
    int to;
    int next;
};
const int inf = 0x3f3f3f;
const int MAXN  = 8e3+10;
const int MAXNN = 2e4+10;

using namespace std;
int first[2*MAXN];
edge e[2*MAXNN];
int color[2*MAXN];
int S[2*MAXN];
int top,l;
int n,m;
int flag;

void init(){
    l = 0;
    memset(first,-1,sizeof(first));
    memset(color,0,sizeof(color));
    flag= 1;
}

void addEdge(int u,int v){
    e[l].st = u;
    e[l].to = v;
    e[l].next = first[u];
    first[u] = l++;
}

int dfs(int v){
    if(color[v]==2)return 0;    //如果深搜到已经染色为2的,不成立
    if(color[v]==1)return 1;
    color[v] = 1;    //本节点染色1
    color[v^1] = 2; //相邻的染色2
    S[top++] = v;
    for(int i=first[v];i!=-1;i=e[i].next){
        if(!dfs(e[i].to))return 0;
    }
    return 1;
}

int main()
{
    int a,b;
    while(scanf("%d%d",&n,&m)!=EOF){
        init();
        for(int i=0;i<m;i++){
            scanf("%d%d",&a,&b);
            a--;
            b--;
            addEdge(a,b^1);
            addEdge(b,a^1);
        }
        int k;
        for(int i=0;i<2*n;i+=2){
            if(!color[i]){
                top = 0;
                if(!dfs(i)){
                    while(top){
                        k = S[--top];
                        color[k] = color[k^1] = 0;
                    }
                    if(!dfs(i+1)){  //2*i-1节点不能选择,必然要选择2*i节点,如果还不满足,说明no solution
                        flag = 0;
                        break;
                    }
                }
            }
        }

        if(!flag){
        cout<<"NIE"<<endl;
        continue;
        }
        for(int i=0;i<2*n;i++){
            if(color[i]==1){
                cout<<i+1<<endl;
            }
        }
    }

    //cout << "Hello world!" << endl;
    return 0;
}
/*
6 6
1 3
4 6
5 7
9 11
10 11
5 12
*/

时间: 2024-10-14 06:27:18

hdu1814 2-SAT 暴力搜的相关文章

POJ 1129 Channel Allocation(暴力搜--涂色问题)

Channel Allocation Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 13295   Accepted: 6806 Description When a radio station is broadcasting over a very large area, repeaters are used to retransmit the signal so that every receiver has a s

hdu1015 dfs暴力搜

很水的题吧,不过以后注意环这种要考虑头尾情况 为了省力素数表范围打错了,太坑了 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <string> #include <queue> #include <stack> #include <algorithm

zoj3944 暴力搜

省赛I题,感觉这题做出来就已经可以铜牌了...好怪的题目,感觉省赛都是挺简单,但是挺容易犯错的题 题目要求找出所有的人, /*OOOOOOOOO*/ 想上面这种所有都是头的竟然就算了9个人,将一个器官的周围可能的情况都尽量归为一个点 遍历每个节点,附件器官清零,遍历模拟的时候还是挺容易犯错的,特别是'\'这种,我就忘了把'('讨论了,wa了三次 #include <iostream> #include <cstdio> #include <cmath> #include

hdu1015 dfs暴力搜索所有情况模板

脑子有点坑,不知道为什么,可能以前遇到阴影了,现在看到dfs暴力搜有种莫名的害怕,总结一下模板吧 这题还是没意思的,直接暴力搜,不过我写的很烂,可能就是这个原因吧,看了别人的模板,觉得不错. 学了个单词”lexicography“ 字典序,又吃了没文化的亏,wa一次 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath>

UVA 10010-- Where&#39;s Waldorf?--暴力串处理

 Where's Waldorf?  Given a m by n grid of letters, ( ), and a list of words, find the location in the grid at which the word can be found. A word matches a straight, uninterrupted line of letters in the grid. A word can match the letters in the grid

2017ecjtu-summer training # 9 HDU 4544

湫湫系列故事--消灭兔子 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 2992    Accepted Submission(s): 987 Problem Description 湫湫减肥 越减越肥! 最近,减肥失败的湫湫为发泄心中郁闷,在玩一个消灭免子的游戏. 游戏规则很简单,用箭杀死免子即可. 箭是一种消耗品,已知有M种不同类型

Sa yo na ra

总想记点些什么. 都快忘了当初是为什么来到这里呢... 2014年10月,友人给我介绍了一门编程竞赛ACM,并给我演示了一下A+B.于是我知道了ACM的含义. 2014年12月,开始水入门题. 2015年1月,第一次参加校赛,在萌新堆中求生存. 2015年2月,看紫书,学算法. 回校后就断断续续地参加一些比赛,成功入坑. 5月,去大连吹海风,吹来了省赛一等奖. 之后就是最要感谢的那个暑假.感谢昌神和学长在大家集体回家度假之时依然在401陪伴着我刷题,以及感谢麟神给我的建议,我也是在那时候学会了很

四方定理(洛谷 1586)

题目描述 四方定理是众所周知的:任意一个正整数n,可以分解为不超过四个整数的平方和.例如:25=12+22+22+42,当然还有其他的分解方案,25=42+32和25=52.给定的正整数n,编程统计它能分解的方案总数.注意:25=42+32和25=32+42视为一种方案. 输入输出格式 输入格式: 第一行为正整数t(≤100),接下来t行,每行一个正整数n(≤32768). 输出格式: 对于每个正整数n,输出方案总数. 输入输出样例 输入样例#1: 1 2003 输出样例#1: 48 /* 先用

maximum sum

uva,10684 1 #include <iostream> 2 #include <cstdio> 3 #define maxn 10005 4 using namespace std; 5 6 int main() 7 { 8 int n; 9 int a[maxn]; 10 while(scanf("%d",&n),n) 11 { 12 for(int i=0;i<n;i++) 13 scanf("%d",&a[