题意:
有n个团队,每个团队有2个人,有m对人之间存在矛盾,问能否在每个团队中只选出一个人组成n个人的和平委员会,并且他们之间不存在有矛盾的人,若能,输出字典序最小的解
分析:
网上基本都是暴力枚举的,没见过更好的算法
对每个团队,优先枚举编号较小的,再把所有必须选择的标记了,将它们存入栈里,如果出现矛盾了,说明这条路行不通,将栈里的取消标记即可
代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e4+14;
int head[MAXN],mark[MAXN],Stack[MAXN],n,m,a,b,cnt,top;
struct edge
{
int to,nxt;
} e[MAXN<<1];
void add(int u,int v)
{
e[++cnt].to = v;
e[cnt].nxt = head[u];
head[u] = cnt;
}
bool dfs(int x)
{
mark[x] = 1;
Stack[++top] = x;
if(mark[x^1]) return false;
for(int i = head[x]; i ; i = e[i].nxt)
{
if(mark[e[i].to]) continue;
if(!dfs(e[i].to)) return false;
}
return true;
}
bool solve()
{
for(int i = 0; i < (n<<1); i += 2)
{
if(!mark[i] && !mark[i^1])
{
top = 0;
if(!dfs(i))
{
while(top--) mark[Stack[top]] = 0;
if(!dfs(i^1)) return false;
}
}
}
return true;
}
void init()
{
cnt = 0,
memset(mark,0,sizeof(mark));
memset(head,0,sizeof(head));
}
int main()
{
while(cin >> n >> m)
{
init();
while(m --)
{
cin >> a >> b;
a--,b--; //方便操作
add(a,b^1);
add(b,a^1);
}
if(solve())
{
for(int i = 0; i < (n<<1); i+=2)
{
if(mark[i]) cout << i+1 <<'\n';
else cout << (i^1)+1 << '\n';
}
}
else puts("NIE");
}
return 0;
}