1 /* 2 HDU - 1824 3 主要是题目描述比较坑爹,注意:队长回家两队员都必须在,只要有一个队员回家,队长都必须在。 4 同时贴上一段看到的让我警醒的话: 5 “这里我说一个细节问题,很多初学者容易忽视 6 那就是边的链接方向。 7 到底是谁指向谁,这个问题,很多初学者容易混淆(比如本人。。) 8 其实问题的关键是考虑,额。。就用这个题来说吧。 9 关键是考虑,一个矛盾关系对里面,到底是两个人是能同时出现,还是能同时不出现 10 这个题里面,队长和队员,是两者可以同时出现的。但是两者却不能同时离开 11 而后面给的关系里面,是指两个人可以同时走,但是却不能同时都在” 12 2—sat 理解拆对象拆分成两个点(T,F) 13 建立好点之间的连通关系 14 我没将队员看成一点,而是每个人作为一个对象 15 */#include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #include <math.h> 19 #include <ctype.h> 20 #include <string> 21 #include <iostream> 22 #include <sstream> 23 #include <vector> 24 #include <queue> 25 #include <stack> 26 #include <map> 27 #include <list> 28 #include <set> 29 #include <algorithm> 30 #define INF 0x3f3f3f3f 31 #define LL long long 32 #define eps 1e-7 33 #define maxn 3100 34 using namespace std;struct TwoSAT{ int n; 35 vector<int> G[maxn*2];//注意点集的大小 36 bool mark[maxn*2];//联系《2-sat算法解析》中的红蓝标色,夫妻不能被标同一种颜色;因为仇人间没有连边,所以在图本身,不可能将两人标同一个颜色 37 int S[maxn*2],c;//存储当前被标记的点,可用于标记的回退 38 bool dfs(int x) 39 { if (mark[x^1]) return false;//真假同时被标记,逻辑矛盾 40 if (mark[x]) return true;//x被标记,意味着下面的节点也被标记,思想是记忆化搜索 41 mark[x]=true; 42 S[c++]=x; for(int i=0;i<G[x].size();i++) if(!dfs(G[x][i])) return false;//同一个强联通分量应该表上同一种颜色 43 return true; 44 } 45 void init(int n) 46 { this->n=n; for(int i=0;i<n*2;i++) G[i].clear(); 47 memset(mark,0,sizeof(mark)); 48 } 49 void add_edge(int u,int v)//这个地方灵活多变一点 50 { 51 G[u].push_back(v);// cout<<u<<"->"<<v<<endl; 52 } void addT(int a,int b,int c) 53 { 54 add_edge(2*a+1,2*b); 55 add_edge(2*a+1,2*c); 56 add_edge(2*b+1,2*a);// add_edge(2*b,2*c); 57 add_edge(2*c+1,2*a);// add_edge(2*c+1,2*b+1); 58 } bool solve() 59 { for(int i=0;i<n*2;i+=2) 60 { if(!mark[i] && !mark[i^1])//真假都没被标记才需dfs,思考一下,原书上写的是[mark+1],这是由i的取值和步长决定的,这里更改,使逻辑含义统一 61 { 62 c=0;//记得清零 63 if(!dfs(i))//将i标记为true 64 { while(c>0) mark[S[--c]]=false; if (!dfs(i^1)) return false;//更改初始标号颜色。只要有一个对象不能“二选一”,则2-sat无解 65 } 66 } 67 } return true; 68 } 69 }sat;//每个人都有一个编号x 70 //2x表示留下,2x+1表示回家 71 int T,M;int nextint() 72 { int x; 73 scanf("%d",&x); return x; 74 }int main() 75 { while(cin>>T>>M) 76 { 77 sat.init(T*3+1); for(int i=0;i<T;i++) 78 { int a,b,c; 79 a=nextint();b=nextint();c=nextint();// cin>>a>>b>>c; 80 sat.addT(a,b,c); 81 } for(int i=0;i<M;i++) 82 { int x,y; 83 x=nextint();y=nextint();// cin>>x>>y; 84 sat.add_edge(2*x,2*y+1); 85 sat.add_edge(2*y,2*x+1); 86 } if (sat.solve()) cout<<"yes"<<endl;else cout<<"no"<<endl; 87 } return 0; 88 }