original link - https://loj.ac/problem/10097
题意:
给出2n个人,每两个( i _ i + 1 i\_i+1 i_i+1)为一对,只能且必须选其中一个。现在有m条限制 ( x , y ) (x,y) (x,y)表示 x , y x,y x,y不能同时选择,求出一个可行方案。
解析:
来分析一下条件:
i i i与 i + 1 i+1 i+1选一个: i → ¬ i + 1 i\to\neg i+1 i→¬i+1, i + 1 → ¬ i i+1\to\neg i i+1→¬i, ¬ i → i + 1 \neg i\to i+1 ¬i→i+1, ¬ i + 1 → i \neg i+1\to i ¬i+1→i
( x , y ) (x,y) (x,y)不能同时选: x → ¬ y x\to \neg y x→¬y, y → ¬ x y\to \neg x y→¬x
所以连上相应的边跑 t a r g a n targan targan就行了。
代码:
#include
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
const int maxn=32009;
const int maxm=40009+2*maxn;
struct SCC {
// edge
int head[maxn],to[maxm],nex[maxm],now;
void add(int a,int b) {
nex[++now]=head[a];
head[a]=now;
to[now]=b;
}
// scc
int low[maxn],dfn[maxn],scc[maxn],Idfs,Iscc;
stack<int>sta;
bool in[maxn];
// init
void init() {
memset(head,0,sizeof head);
memset(dfn,0,sizeof dfn);
memset(in,0,sizeof in);
now=0;
Idfs=Iscc=0;
while(!sta.empty())
sta.pop();
}
// deal
void tarjan(int p) {
low[p]=dfn[p]=++Idfs;
sta.push(p);
in[p]=1;
for(int i=head[p]; i; i=nex[i]) {
int q=to[i];
if(!dfn[q])
tarjan(q),low[p]=min(low[p],low[q]);
else if(in[q])
low[p]=min(low[p],dfn[q]);
}
if(low[p]==dfn[p]) {
++Iscc;
while(1) {
int q=sta.top();
sta.pop();
scc[q]=Iscc;
in[q]=0;
if(p==q)
break;
}
}
}
} E;
int main() {
for(int n,m;scanf("%d%d",&n,&m)!=EOF;){
E.init();
rep(i,1,(n<<1)){
E.add(i+2*n,i+1);
E.add(i+1+2*n,i);
E.add(i,i+1+2*n);
E.add(i+1,i+2*n);
i++;
}
rep(i,1,m){
int a,b;scanf("%d%d",&a,&b);
E.add(a,b+2*n);
E.add(b,a+2*n);
}
rep(i,1,(n<<2)){
if(!E.dfn[i])E.tarjan(i);
}
int cant=0;
rep(i,1,(n<<1)){
if(E.scc[i]==E.scc[i+2*n]){
cant=1;break;
}
}
if(cant){
printf("NIE\n");
continue;
}
rep(i,1,(n<<1)){
if(E.scc[i]<E.scc[i+2*n]){
printf("%d\n",i);
}
}
}
}