[POI2001]Peaceful Commission
题目大意:
有n个国家要派代表开会,每个国家有两个代表可供选择。
有m对代表有仇,不能同时开会。
若每个国家只能派一个代表开会,问是否存在一种方案,使得每个国家都能正常参会?
如果有,输出字典序最小的一种。
思路:
2-SAT经典模型。
如果两个代表之间有仇,那么就给其中一个代表a连一条通向另一国家另一代表b的有向边,表示选a后一定要选b。
判定时就用Tarjan缩点,如果同一国家两个代表在同一个强连通分量中,那么说明两个代表必须同时参加或不参加,这是不合法的。
构造字典序最小的方案时,可以从小到大枚举每一个代表,然后DFS选定该代表后,必须选的其它代表,如果必须选的的代表和已选代表矛盾,则不加入。
1 #include<stack> 2 #include<cstdio> 3 #include<cctype> 4 #include<vector> 5 inline int getint() { 6 register char ch; 7 while(!isdigit(ch=getchar())); 8 register int x=ch^'0'; 9 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 10 return x; 11 } 12 const int N=16000; 13 std::stack<int> s; 14 std::vector<int> e[N<<1]; 15 bool ins[N<<1],select[N<<1]; 16 int dfn[N<<1],low[N<<1],scc[N<<1],cnt,id; 17 inline void add_edge(const int &u,const int &v) { 18 e[u].push_back(v); 19 } 20 void tarjan(const int &x) { 21 s.push(x); 22 ins[x]=true; 23 dfn[x]=low[x]=++cnt; 24 for(unsigned i=0;i<e[x].size();i++) { 25 const int &y=e[x][i]; 26 if(!dfn[y]) { 27 tarjan(y); 28 low[x]=std::min(low[x],low[y]); 29 } else if(ins[y]) { 30 low[x]=std::min(low[x],dfn[y]); 31 } 32 } 33 if(low[x]==dfn[x]) { 34 id++; 35 int y=-1; 36 while(y!=x) { 37 y=s.top(); 38 s.pop(); 39 ins[y]=false; 40 scc[y]=id; 41 } 42 } 43 } 44 bool dfs(const int &x) { 45 if(select[x^1]) return false; 46 s.push(x); 47 select[x]=true; 48 for(unsigned i=0;i<e[x].size();i++) { 49 const int &y=e[x][i]; 50 if(select[y]) continue; 51 if(!dfs(y)) return false; 52 } 53 return true; 54 } 55 inline void reset(const int &n) { 56 cnt=id=0; 57 for(register int i=0;i<n<<1;i++) { 58 dfn[i]=low[i]=select[i]=0; 59 e[i].clear(); 60 } 61 } 62 int main() { 63 int n,m; 64 while(~scanf("%d%d",&n,&m)) { 65 while(m--) { 66 const int u=getint()-1,v=getint()-1; 67 add_edge(u,v^1); 68 add_edge(v,u^1); 69 } 70 for(register int i=0;i<n<<1;i++) { 71 if(!dfn[i]) tarjan(i); 72 } 73 for(register int i=0;i<n;i++) { 74 if(scc[i<<1]==scc[i<<1|1]) { 75 puts("NIE"); 76 goto Next; 77 } 78 } 79 for(register int i=0;i<n<<1;i++) { 80 if(!select[i]&&!select[i^1]) { 81 if(dfs(i)) { 82 while(!s.empty()) s.pop(); 83 } else { 84 while(!s.empty()) { 85 const int x=s.top(); 86 s.pop(); 87 select[x]=false; 88 } 89 } 90 } 91 } 92 for(register int i=0;i<n<<1;i++) { 93 if(select[i]) printf("%d\n",i+1); 94 } 95 Next: 96 reset(n); 97 } 98 return 0; 99 }