hihocoder #1468 : 2-SAT·hihoCoder新春晚会 2-SAT

题目链接:

http://hihocoder.com/problemset/problem/1468

题意:

hihoCoder新春晚会正在紧张地筹备中。晚会分为上半场和下半场,总导演小Hi现在要为N个节目安排演出时间(上半场或下半场)。为了描述方便,我们将第i个节目对应两个编号2i-1和2i,分别表示把第i个节目安排在上半场和下半场。

由于演员、道具和布景的限制。有些安排之间存在冲突,比如编号1的安排和编号4的安排有冲突,意味着"把第1个节目安排在上半场"同"把第2个节目安排在下半场"有冲突。

现在小Hi手里有M对编号,表示冲突的节目安排。他的任务是帮助主办方安排出节目演出的合理时间。

输入

第一行包含两个非负整数n和m(n≤8000,m≤20000),代表有n个节目和m对冲突。

接下来m行每行两个数x和y,表示编号x和编号y冲突。

输出

输出n行,每行一个数,从小到大输出最后进行演出的编号。若有多解,则输出字典序最小的。无解则输出NIE。

样例输入

3 2
1 3
2 4

样例输出

1
4
5

思路:

u和v不能同时出现,所以对应的边就是 u->(v的另一个),v->(u的另一个) 这两条,我们tarjan求出强联通分量,判断是否矛盾,如果r[i*2]==r[i*2-1]那么就矛盾,否则一定有解,因为要求字典序最小,所以我们编号从小的开始便利,如果这个节目上半场和下半场都没访问过,那么从上半场bfs[字典序的限制],得到一条符合规则的链,如果出现矛盾,也就是也访问过这条链上某个点对应的相反的点,那么就从当前节目的下半场bfs过去。 说的很迷,,看代码把

代码:

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 #define MS(a) memset(a,0,sizeof(a))
  5 #define MP make_pair
  6 #define PB push_back
  7 const int INF = 0x3f3f3f3f;
  8 const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
  9 inline ll read(){
 10     ll x=0,f=1;char ch=getchar();
 11     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
 12     while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
 13     return x*f;
 14 }
 15 //////////////////////////////////////////////////////////////////////////
 16 const int maxn = 1e5+10;
 17
 18 vector<int> g[maxn];
 19
 20 void add(int u,int v){
 21     g[u].push_back(v);
 22 }
 23
 24 int low[maxn],dfn[maxn],vis[maxn],ins[maxn],r[maxn],tot;
 25 stack<int> s;
 26 void tarjan(int u){
 27     low[u]=dfn[u] = ++tot;
 28     vis[u]=ins[u] = 1;
 29     s.push(u);
 30     for(int i=0; i<(int)g[u].size(); i++){
 31         int v = g[u][i];
 32         if(!vis[v]){
 33             tarjan(v);
 34             low[u] = min(low[u],low[v]);
 35         }else if(ins[v]){
 36             low[u] = min(low[u],dfn[v]);
 37         }
 38     }
 39
 40     if(dfn[u] == low[u]){
 41         int t;
 42         do{
 43             t = s.top(); s.pop();
 44             r[t] = u;
 45             ins[t] = 0;
 46         }while(t != u);
 47     }
 48 }
 49
 50 int tmp[maxn],ans[maxn];
 51
 52 void bfs(int u){
 53     queue<int> q;
 54     q.push(u); vis[u] = 1;
 55     tmp[0] = 0;
 56     while(!q.empty()){
 57         int now = q.front(); q.pop();
 58         tmp[++tmp[0]] = now;
 59         for(int i=0; i<(int)g[now].size(); i++){
 60             int v = g[now][i];
 61             if(vis[v]) continue;
 62             vis[v] = 1;
 63             q.push(v);
 64         }
 65     }
 66 }
 67
 68 bool judge(){
 69     for(int i=1; i<=tmp[0]; i++){
 70         if(vis[tmp[i]+(tmp[i]&1 ? 1 : -1)]) return false;
 71     }
 72     return true;
 73 }
 74
 75 int main(){
 76     int n,m;
 77     cin >> n >> m;
 78     for(int i=0; i<m; i++){
 79         int u,v; scanf("%d%d",&u,&v);
 80         add(u,v+((v&1)?1:-1));
 81         add(v,u+((u&1)?1:-1));
 82     }
 83     for(int i=1; i<=2*n; i++){
 84         if(!dfn[i]) tarjan(i);
 85     }
 86
 87     for(int i=1; i<2*n; i+=2){
 88         if(r[i] == r[i+1]){
 89             puts("NIE");
 90             return 0;
 91         }
 92     }
 93
 94     MS(vis);
 95     for(int i=1; i<=n; i++){
 96         if(!vis[i*2] && !vis[i*2-1]){
 97             bfs(i*2-1);
 98             if(!judge()){
 99                 for(int j=1; j<=tmp[0]; j++) vis[tmp[j]] = 0;
100                 bfs(i*2);
101             }
102             for(int j=1; j<=tmp[0]; j++) ans[++ans[0]] = tmp[j];
103         }
104     }
105     sort(ans+1,ans+ans[0]+1);
106     for(int i=1; i<=n; i++){
107         cout << ans[i] << endl;
108     }
109
110     return 0;
111 }
时间: 2024-10-15 18:55:41

hihocoder #1468 : 2-SAT·hihoCoder新春晚会 2-SAT的相关文章

hiho一下第134周 1468 : 2-SAT&#183;hihoCoder新春晚会

1468 : 2-SAT·hihoCoder新春晚会 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 hihoCoder新春晚会正在紧张地筹备中.晚会分为上半场和下半场,总导演小Hi现在要为N个节目安排演出时间(上半场或下半场).为了描述方便,我们将第i个节目对应两个编号2i-1和2i,分别表示把第i个节目安排在上半场和下半场. 由于演员.道具和布景的限制.有些安排之间存在冲突,比如编号1的安排和编号4的安排有冲突,意味着"把第1个节目安排在上半场"同&q

8.3吝啬SAT问题

吝啬SAT问题是这样的:给定一组子句(每个子句都是其中文字的析取)和整数k,求一个最多有k个变量为true的满足赋值--如果该赋值存在.证明吝啬SAT是NP-完全问题. 1.易知吝啬SAT的解可以在多项式时间内验证,因此属于NP问题. 2.如果我们把吝啬SAT问题中的k设置为输入的数目,那么SAT问题就可以规约到吝啬SAT问题,所以吝啬SAT问题是np-完全问题.

trie tree(字典树)

hihocoder题目(http://hihocoder.com/problemset):#1014 trie树 1 #include <iostream> 2 using namespace std; 3 class trieTree 4 { 5 public: 6 trieTree() 7 { 8 isword=false; 9 for (int i=0;i<26;i++) 10 { 11 next[i]=NULL; 12 } 13 } 14 ~trieTree() 15 { 16

关于动态规划的理解

动态规划是个比较有趣的算法,第一次接触动态规划也是从一个比较特别的教程开始的,这里贴出原文地址http://blog.csdn.net/woshioosm/article/details/7438834 看完原文回到这里,其实我觉得很多像我这种C语言刚刚入门的人,只理解到了动态规划的转移方程,以原文中的例子为例: 当mineNum = 0且people >= peopleNeeded[mineNum]时 f(people,mineNum) = gold[mineNum] 当mineNum = 0

【BZOJ1717】产奶的模式(后缀数组)

[BZOJ1717]产奶的模式(后缀数组) 题面 权限题 hihocoder 洛谷 题解 \(hihocoder\)里面讲的非常好了 这题要求的就是最长可重叠重复K次子串 所谓相同的子串 我们可以理解为如果有两个后缀的前缀相同 那么就有一个相同的子串 如果两个后缀的前缀相同 那么他们在\(SA\)中的排名是接近的 再说清楚点 如果两个后缀的前缀相同 必然是在后缀排序中一段连续的后缀都拥有这个相同的前缀 因此,求出\(height\)数组之后 考虑如何计算答案: 直接搞显然搞不出来 因此二分一下答

算法概论第八章课后习题8.3

8.3 吝啬SAT问题是这样的:给定一组子句(每个子句都是其中文字的析取)和整数k,求一个最多有k个变量为true的满足赋值--如果该赋值存在.证明吝啬SAT是NP-完全问题. 证明: 补充一下SAT问题的概念:SAT问题是指是否存在一组对所有布尔变量的赋值(TRUE或FALSE),使得整个合取范式取指为真. 根据书本8.2章的定义:称一个搜索问题是NP-完全的,是指其它所有搜索问题都可以归约到它. 从定义可知,证明一个问题是NP-完全问题有两步,第一步是证明该问题是一个NP问题,第二步是证明其

iptables详解

IPtables(包过滤型防火墙)是一个工作在linux内核中且有连接追踪的包过滤型防火墙 Firewall(防火墙):是一个用来做网络隔离.工作在网络边缘的组件.防火墙可以根据事先定义的规则对进出本网络的数据报文进行匹配检测,并对其匹配的报文做出相应的处理.简单来说就是:根据规则,匹配报文,做出处理. 防火墙分类: 主机防火墙 网络防火墙 硬件防火墙(硬件个软件逻辑) 软件防火墙(软件逻辑,灵活) IPchains:规则连,自上而下一条条的对报文进行规则匹配,一旦被某个规则匹配就按照这个规则的

Linux面试题

Linux面试题总结一下   一.有文件file1  1.查询file1 里面空行的所在行号  awk '{if($0~/^$/)print NR}' file  or  grep -n ^$ file |awk 'BEGIN{FS=":"}{print $1}'  2.查询file1 以abc 结尾的行  grep abc$ file1  3.打印出file1 文件第1 到第3 行  sed -n '1,3p' file1  head -3 file1  二.如何将本地80 端口的请

《算法概论》第八章的一些课后题目 关于NP-Complete Problem

8.3 STINGY SAT STINGY SAT is the following problem: given a set of clauses (each a disjunction of literals) and an integer k, find a satisfying assignment in which at most k variables are true, if such an assignment exists. Prove that STINGY SAT is N