题意
现在有n个党派,每个党派拥有两个候选代表,第i个党派的候选代表为2i-1和2i,两个党派候选人只会有一个去参加会议,此外还有m对候选人互相看不顺眼,只能去其中一个,求字典序最小的代表人选。
思路
一个比较明显的2-SAT问题,但是需要输出最小解,所以似乎不可以用传统的拓扑排序寻找可行解,于是采取了DFS解法,复杂度O(nm),其能选取出最小解的原因应该是采取了顺序的遍历方式。
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
bool mark[maxn];
int k,m,n,cnt,s[maxn],head[maxn];
struct node
{
int to,next;
}a[maxn];
void add(int u,int v)
{
a[++k].next=head[u];
a[k].to=v;
head[u]=k;
}
void init()
{
k=0;
memset(head,0,sizeof head);
}
bool dfs(int x)
{
if(mark[x^1])
return false;
if(mark[x])
return 1;
s[++cnt]=x;
mark[x]=1;
for(int i=head[x];i;i=a[i].next)
{
int to=a[i].to;
if(!dfs(to))
return false;
}
return true;
}
bool twosat()
{
memset(mark,0,sizeof mark);
for(int i=0;i<2*n;i+=2)
{
if(!mark[i]&&!mark[i^1])
{
cnt=0;
if(!dfs(i))
{
while(cnt)
mark[s[cnt--]]=false;
if(!dfs(i^1))
return false;
}
}
}
return true;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
while(cin>>n>>m)
{
init();
for(int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
u--;v--;
add(u,v^1);
add(v,u^1);
}
if(twosat())
{
for(int i=0;i<2*n;i+=2)
{
if(mark[i])
cout<<i+1<<endl;
else
cout<<i+2<<endl;
}
}
else
cout<<"NIE"<<endl;
}
return 0;
}