HDU1824(2-SAT)

Let's go home

Time Limit: 10000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2103    Accepted Submission(s): 903


Problem Description

小时候,乡愁是一枚小小的邮票,我在这头,母亲在那头。
                        —— 余光中

集训是辛苦的,道路是坎坷的,休息还是必须的。经过一段时间的训练,lcy决定让大家回家放松一下,但是训练还是得照常进行,lcy想出了如下回家规定,每一个队(三人一队)或者队长留下或者其余两名队员同时留下;每一对队员,如果队员A留下,则队员B必须回家休息下,或者B留下,A回家。由于今年集训队人数突破往年同期最高记录,管理难度相当大,lcy也不知道自己的决定是否可行,所以这个难题就交给你了,呵呵,好处嘛~,免费**漂流一日。
 

Input

第一行有两个整数,T和M,1<=T<=1000表示队伍数,1<=M<=5000表示对数。
接下来有T行,每行三个整数,表示一个队的队员编号,第一个队员就是该队队长。
然后有M行,每行两个整数,表示一对队员的编号。
每个队员只属于一个队。队员编号从0开始。
 

Output

可行输出yes,否则输出no,以EOF为结束。
 

Sample Input

1 2 0 1 2 0 1 1 2 2 4 0 1 2 3 4 5 0 3 0 4 1 3 1 4
 

Sample Output

yes no
 

Author

威士忌
 

 

Source

 
2-SAT 建图
  1 //2017-08-27
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 #include <algorithm>
  6 #include <vector>
  7 
  8 using namespace std;
  9 
 10 const int N = 5010;
 11 const int M = N*N;
 12 int head[N], rhead[N], tot, rtot;
 13 struct Edge{
 14     int to, next;
 15 }edge[M], redge[M];
 16 
 17 void init(){
 18     tot = 0;
 19     rtot = 0;
 20     memset(head, -1, sizeof(head));
 21     memset(rhead, -1, sizeof(rhead));
 22 }
 23 
 24 void add_edge(int u, int v){
 25     edge[tot].to = v;
 26     edge[tot].next = head[u];
 27     head[u] = tot++;
 28 
 29     redge[rtot].to = u;
 30     redge[rtot].next = rhead[v];
 31     rhead[v] = rtot++;
 32 }
 33 
 34 vector<int> vs;//后序遍历顺序的顶点列表
 35 bool vis[N];
 36 int cmp[N];//所属强连通分量的拓扑序
 37 
 38 //input: u 顶点
 39 //output: vs 后序遍历顺序的顶点列表
 40 void dfs(int u){
 41     vis[u] = true;
 42     for(int i = head[u]; i != -1; i = edge[i].next){
 43         int v = edge[i].to;
 44         if(!vis[v])
 45           dfs(v);
 46     }
 47     vs.push_back(u);
 48 }
 49 
 50 //input: u 顶点编号; k 拓扑序号
 51 //output: cmp[] 强连通分量拓扑序
 52 void rdfs(int u, int k){
 53     vis[u] = true;
 54     cmp[u] = k;
 55     for(int i = rhead[u]; i != -1; i = redge[i].next){
 56         int v = redge[i].to;
 57         if(!vis[v])
 58           rdfs(v, k);
 59     }
 60 }
 61 
 62 //Strongly Connected Component 强连通分量
 63 //input: n 顶点个数
 64 //output: k 强连通分量数;
 65 int scc(int n){
 66     memset(vis, 0, sizeof(vis));
 67     vs.clear();
 68     for(int u = 0; u < n; u++)
 69       if(!vis[u])
 70         dfs(u);
 71     int k = 0;
 72     memset(vis, 0, sizeof(vis));
 73     for(int i = vs.size()-1; i >= 0; i--)
 74       if(!vis[vs[i]])
 75         rdfs(vs[i], k++);
 76     return k;
 77 }
 78 
 79 void solve(int n){
 80     for(int i = 0; i < n; i++){
 81         if(cmp[i] == cmp[i+n]){//a和NOT a在同一个强连通分量中,布尔方程无解
 82             cout<<"no"<<endl;
 83             return;
 84         }
 85     }
 86     cout<<"yes"<<endl;//布尔方程有解
 87     return;
 88 }
 89 
 90 int main()
 91 {
 92     std::ios::sync_with_stdio(false);
 93     //freopen("inputB.txt", "r", stdin);
 94     int t, m;
 95     while(cin>>t>>m){
 96         init();
 97         int MAXID = 3*t;
 98         int a, b, c;
 99         for(int i = 0; i < t; i++){
100             cin>>a>>b>>c;
101             add_edge(a+MAXID, b);// NOT a -> b
102             add_edge(a+MAXID, c);// NOT a -> c
103             add_edge(b+MAXID, a);// NOT b -> a
104             add_edge(c+MAXID, a);// NOT c -> a
105             //add_edge(b, c);
106             //add_edge(c, b);
107         }
108         for(int i = 0; i < m; i++){
109             cin>>a>>b;
110             add_edge(a, b+MAXID);
111             add_edge(b, a+MAXID);
112         }
113         scc(MAXID<<1);
114         solve(MAXID);
115     }
116     return 0;
117 }
原文地址:https://www.cnblogs.com/Penn000/p/7440022.html