3 2 1 3 2 4
1 4 5
这道题求的是可行解中的最小序列。
我们给结点染色,假设白色是未染色,红色是要选取的结点,蓝色是抛弃的结点。
首先从第一个点开始染色,染成红色,同时将同组另一节点染成蓝色,然后将这个点的所有后继结点也染成红色,同时开一个数组记录都染了哪些结点。如果后来发现某结点的后继是蓝色,说明本次染色失败,因为碰到了矛盾(假如一个结点被选取,那么所有后继肯定也得全部选取)。那么因为刚才染色的时候记录了染色的结点,靠这个数组将结点全部还原回白色。然后从第二个结点开始探索,直到全部染色完毕,最后的红色结点就是答案。
0表示未染色
1表示染成红色
2表示染成蓝色
本题解题思路来自http://blog.163.com/shengrui_step/blog/static/20870918720141201262750/
谢谢Shengrui的精准阐述
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <climits> 7 #include <vector> 8 #include <queue> 9 #include <cstdlib> 10 #include <string> 11 #include <set> 12 #include <stack> 13 #define LL long long 14 #define pii pair<int,int> 15 #define INF 0x3f3f3f3f 16 using namespace std; 17 const int maxn = 20010; 18 vector<int>g[maxn]; 19 int color[maxn],tmp[maxn],tot,n,m; 20 bool dfs(int u){ 21 if(color[u] == 1) return true; 22 if(color[u] == 2) return false; 23 color[u] = 1; 24 tmp[tot++] = u; 25 color[(u-1^1)+1] = 2; 26 for(int i = 0; i < g[u].size(); i++) 27 if(!dfs(g[u][i])) return false; 28 return true; 29 } 30 bool solve(){ 31 memset(color,0,sizeof(color)); 32 for(int i = 1; i <= n<<1; i++){ 33 if(color[i] == 0){ 34 tot = 0; 35 if(!dfs(i)){ 36 for(int j = 0; j < tot; j++){ 37 color[tmp[j]] = 0; 38 color[(tmp[j]-1^1)+1] = 0; 39 } 40 if(!dfs((i-1^1)+1)) return false; 41 } 42 } 43 } 44 return true; 45 } 46 int main() { 47 int x,y; 48 while(~scanf("%d %d",&n,&m)){ 49 for(int i = 1; i <= n<<1; i++) g[i].clear(); 50 for(int i = 0; i < m; i++){ 51 scanf("%d %d",&x,&y); 52 g[x].push_back((y-1^1)+1); 53 g[y].push_back((x-1^1)+1); 54 } 55 if(solve()){ 56 for(int i = 1; i <= n<<1; i++) 57 if(color[i] == 1) printf("%d\n",i); 58 }else puts("NIE"); 59 } 60 return 0; 61 }
原文:http://www.cnblogs.com/crackpotisback/p/4005334.html