題目連結:
http://acm.hdu.edu.cn/showproblem.php?pid=1824
【題目】
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 20 1 20 11 22 40 1 23 4 50 30 41 31 4
Sample Output
yesno
【思路】每一個隊伍中,要麼隊長留下,要麼另外兩個隊員留下,這是一個矛盾對,可以把隊長看成一個點,把兩個隊員也抽象成一個點,把他們進行一個映射, 對於a,b,c, !a->b, !b->a, !c->a, 即f[a] = b, f[b]=a, f[c]=a,然後直接用2-SAT判斷即可。【代碼】
#include<iostream> #include<cstdio>#include<cstring>using namespace std;typedef long long int64;const int MAXN = 3010;const int VN = MAXN*2;const int EN = VN*2;int t, m;int f[MAXN];struct Edge{ int v, next;};struct Graph{public: void init(){ size = 0; memset(head, -1, sizeof(head)); } void addEdge(int u, int v){ E[size].v = v; E[size].next = head[u]; head[u] = size++; }public: int head[VN]; Edge E[EN];private: int size; }g;class Tow_Sat{public: bool check(const Graph&g, const int n){ scc(g, n); for(int i=0; i<n; ++i) if(belong[3*i] == belong[f[3*i]] || belong[3*i+1] == belong[f[3*i+1]]) return false; return true; }private: int top, bcnt, idx; int DFN[VN]; int low[VN]; int belong[VN]; int sta[VN]; bool inStack[VN]; void targan(const Graph&g, const int u){ int v; DFN[u] = low[u] = ++idx; sta[top++] = u; inStack[u] = true; for(int e=g.head[u]; e!=-1; e=g.E[e].next){ v = g.E[e].v; if(DFN[v] < 0){ targan(g, v); low[u] = min(low[u], low[v]); }else if(inStack[v]){ low[u] = min(low[u], DFN[v]); } } if(DFN[u] == low[u]){ ++bcnt; do{ v = sta[--top]; inStack[v] = false; belong[v] = bcnt; }while(u != v); } } void scc(const Graph&g, int n){ top = bcnt = idx = 0; memset(DFN, -1, sizeof(DFN)); memset(inStack, 0, sizeof(inStack)); for(int i=0; i<3*n; ++i) if(DFN[i] < 0) targan(g, i); }}sat;int main(){ int a,b,c; while(~scanf("%d%d", &t, &m)){ g.init(); for(int i=0; i<t; ++i){ scanf("%d%d%d", &a,&b,&c); g.addEdge(b, c); g.addEdge(c, b); f[a] = b; f[b] = f[c] = a; } bool flag = true; for(int i=0; i<m; ++i){ scanf("%d%d", &a,&b); g.addEdge(a, f[b]); g.addEdge(b, f[a]); } if(flag && sat.check(g, t)) puts("yes"); else puts("no"); } return 0;}