简单概括一下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);
题目:

4878

被折叠的 条评论
为什么被折叠?



