[HDU 1814] Peaceful Commission

一、題目

點此看題

二、解法

這就是2-sat\text{2-sat}帶字典序最小解的經典問題,時間複雜度O(n2)O(n^2),還是結合代碼講更好:

#include <cstdio>
#include <iostream>
using namespace std;
const int M = 20005;
int read()
{
    int num=0,flag=1;char c;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9')num=(num<<3)+(num<<1)+(c^48),c=getchar();
    return num*flag;
}
int n,m,tp,tot,s[M],f[M],vis[M];//vis表示當前是否確定選取 
struct edge
{
    int v,next;
}e[2*M];
void add(int u,int v)
{
    e[++tot]=edge{v,f[u]},f[u]=tot;
}
int dfs(int u)//表示選取u是否成功,會修改vis 
{
	if(vis[u]) return 1;//已經成功了 
	if(vis[u^1]) return 0;//另一個成功了,這一個不能成功 
	vis[u]=1;
	s[++tp]=u;//加入棧中,方便刪除 
	for(int i=f[u];i;i=e[i].next)
	{
		int v=e[i].v;
		if(!dfs(v)) return 0;//如果相連的點選取失敗這個點必失敗 
	}
	return 1;//否則成功 
}
signed main()
{
	while(~scanf("%d %d",&n,&m))
	{
		int fl=1;tot=0;
		for(int i=0;i<2*n;i++)
			f[i]=vis[i]=0;
		for(int i=1;i<=m;i++)
		{
			int a=read()-1,b=read()-1;//減個1,方便異或1取另一個 
			add(a,b^1);
			add(b,a^1);
		}
		for(int i=0;i<n;i++)
		{
			if(vis[2*i] || vis[2*i+1]) continue;
			tp=0;//在這裏清 
			if(!dfs(2*i))//先判斷能不能選2*i 
			{
				while(tp) vis[s[tp--]]=0;
				if(!dfs(2*i+1))//再來嘗試選2*i+1,不行的話無解 
				{
					puts("NIE");
					fl=0;
					break;
				}
			}
		}
		if(fl==0) continue;
		for(int i=0;i<2*n;i++)
			if(vis[i]) printf("%d\n",i+1);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章