2-sat

简单概括一下2-sat:

给定一个布尔方程判断是否存在一组变量的真值指派是方程为真。特别地,求解形如(a∨b)∧(c∨d)∧...的方程为2-sat。

 

How to?

把每一个(a∨b)改写为(!a=>b∧!b=>a)的样子(...你们凑合着看吧,那个=>是蕴涵的意思),然后根据蕴涵的关系连边,再求一发强连通分量,如果a和!a在同一个强连通分量就无解,否则:若x所在强连通分量的拓扑序在!x之后就令x为真,是一组合法的解。

 

QAQ还是给一段代码吧..感觉这代码真是丑得不忍直视

连边:(摘自poj3683)

 

for(i=1;i<=n;i++)
	for(j=1;j<=n;j++)
		if(i!=j)
		{
			if(!(t[i]<=s[j]||t[j]<=s[i])) 
				{a[i].push_back(j+n);a[j].push_back(i+n);}
			if(!(t[i]<=s[j+n]||t[j+n]<=s[i])) 
				{a[i].push_back(j);a[j+n].push_back(i+n);}
			if(!(t[i+n]<=s[j]||t[j]<=s[i+n])) 
				{a[i+n].push_back(j+n);a[j].push_back(i);}
			if(!(t[i+n]<=s[j+n]||t[j+n]<=s[i+n])) 
				{a[i+n].push_back(j);a[j+n].push_back(i);}
		}


判断:(还是摘自poj3683)

 

 

	for(i=1;i<=n;i++)
		if(v[i]==v[i+n]) {printf("NO\n");return 0;}
	printf("YES\n");
	for(i=1;i<=n*2;i++) b[i].clear();
	for(i=1;i<=n*2;i++)
		for(j=0;j<a[i].size();j++)
			if(v[i]!=v[a[i][j]]) 
				{b[v[a[i][j]]].push_back(v[i]);rd[v[i]]++;}
	cnt=0;
	for(i=1;i<=ct;i++) if(!rd[i]) q.push(i);
	while(!q.empty())
	{
		int p=q.front();q.pop();tp[p]=++cnt;
		for(i=0;i<b[p].size();i++)
			if(b[p][i]) 
			{
				rd[b[p][i]]--;
				if(!rd[b[p][i]]) {q.push(b[p][i]);b[p][i]=0;}
			}
	}
	for(i=1;i<=n;i++)
		if(tp[v[i]]<tp[v[i+n]]) printf("%02d:%02d %02d:%02d\n",s[i]/60,s[i]%60,t[i]/60,t[i]%60);
		else printf("%02d:%02d %02d:%02d\n",s[i+n]/60,s[i+n]%60,t[i+n]/60,t[i+n]%60);

 

 

 

 

 

 

题目:

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值