矛盾的情况为:
存在Ai,使得Ai既必须被选又不可选。
枚举每一对尚未确定的Ai, Ai‘ ,任选1个,推导出相关的组,若不矛盾,则可选择;否则选另1个,同样推导。若矛盾,问题必定无解。
此算法正确性简要说明:
由于Ai,Ai ' 都是尚未确定的,它们不与之前的组相关联,前面的选择不会影响Ai, Ai ' 。
算法的时间复杂度在最坏的情况下为O(nm)。
在这个算法中,并没有很好的利用图中边的对称性
//#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
const int M =150;
// 染色法 (O(NM)算法 可以得到字典序最小的解)
const int MAXN=20020;
const int MAXM=100010;
struct node
{
int to,next;
} edge[MAXM];
int head[MAXN],tot;
void init()
{
tot=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v)
{
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}
bool vis[MAXN]; //染色标记,为true表示选择
int s[MAXN],top; //栈
bool dfs(int u)
{
if(vis[u^1])
return 0;
if(vis[u])
return 1;
vis[u]=1;
s[top++]=u;
for(int i=head[u]; ~i; i=edge[i].next)
{
if(!dfs(edge[i].to))
return 0;
}
return 1;
}
bool twosat(int n)
{
memset(vis,0,sizeof(vis));
for(int i=0; i<n; i+=2)
{
if(vis[i]||vis[i^1])
continue;
top=0;
if(!dfs(i))
{
while(top)
vis[s[--top]]=0;
if(!dfs(i^1))
return 0;
}
}
return 1;
}
int main()
{
int n,m;
int u,v;
while(~scanf("%d%d",&n,&m))
{
init();
while(m--)
{
scanf("%d%d",&u,&v);
u--;
v--;
add(u,v^1);
add(v,u^1);
}
if(twosat(2*n))
{
for(int i=0;i<2*n;++i)
{
if(vis[i])
printf("%d\n",i+1);
}
}
else
printf("NIE\n");
}
return 0;
}