2-SAT经典问题
#include<cstdio>
#include<string.h>
#include<math.h>
#include<stack>
#define N 2010
#define M N*N*3
using namespace std;
struct edge{
int v,next;
}edge[M];
int n;
int s[N],t[N],seq[N];
int cnt,head1[N],head2[N],head3[N];
int scc,Index,dfn[N],low[N],belong[N];
int top,sstack[N];
bool instack[N],vis[N];
int d[N],col[N];
void addedge(int u,int v,int *head)
{
edge[cnt].v=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
int MAX(int a,int b){
return a>b?a:b;
}
int MIN(int a,int b){
return a>b?b:a;
}
void tarjan(int u)
{
dfn[u]=low[u]=++Index;
sstack[++top]=u;
instack[u]=true;
for(int j=head1[u];j!=-1;j=edge[j].next)
{
int v=edge[j].v;
if(dfn[v]==0)
{
tarjan(v);
low[u]=MIN(low[v],low[u]);
}
else if(instack[v])
{
low[u]=MIN(low[u],dfn[v]);
}
}
if(dfn[u]==low[u])
{
scc++;
while(1)
{
int tmp=sstack[top--];
addedge(scc,tmp,head3);
instack[tmp]=false;
belong[tmp]=scc;
if(tmp==u) break;
}
}
}
void make_graph(){
int i,j;
for(i=1;i<=2*n;i++){
for(j=head1[i];j!=-1;j=edge[j].next){
int v=edge[j].v;
if(belong[i]!=belong[v]){
addedge(belong[v],belong[i],head2);
}
}
}
}
bool ok(int i,int j){
if(s[i]>=t[j] || t[i]<=s[j])
return false;
return true;
}
bool check(){
int i;
for(i=1;i<=n;i++){
if(belong[i*2]==belong[i*2-1])
return false;
}
return true;
}
void topo(){
int i,j;
top=0;
stack<int>sta;
for(i=1;i<=scc;i++)
for(j=head2[i];j!=-1;j=edge[j].next)
d[edge[j].v]++;
for(i=1;i<=scc;i++){
if(!d[i])
sta.push(i);
}
while(!sta.empty()){
int u=sta.top();
sta.pop();
seq[++top]=u;
for(i=head2[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
d[v]--;
if(!d[v])
sta.push(v);
}
}
}
void paint(int u){
int k;
for(k=head2[u];k!=-1;k=edge[k].next)
if(col[edge[k].v]==0){
col[edge[k].v]=-1;
paint(edge[k].v);
}
}
void colour(){
int i,j,k;
for(j=1;j<=top;j++){
int u=seq[j];
if(col[u]==0){
col[u]=1;
for(i=head3[u];i!=-1;i=edge[i].next){ //枚举连通分量u中的点
int v=edge[i].v;
if(col[belong[((v-1)^1)+1]]==0){
col[belong[((v-1)^1)+1]]=-1;
paint(belong[((v-1)^1)+1]); //paint函数表示把新建的图中(belong[((v-1)^1)+1)的前向节点删去
}
}
}
}
}
void printf_path(){
int i,j;
for(i=1;i<=n;i++){
if(col[belong[i*2]]==1){
printf("%02d:%02d %02d:%02d\n",s[i*2]/60,s[i*2]%60,t[i*2]/60,t[i*2]%60);
}
else{
printf("%02d:%02d %02d:%02d\n",s[i*2-1]/60,s[i*2-1]%60,t[i*2-1]/60,t[i*2-1]%60);
}
}
}
int main(){
int i,j;
scanf("%d",&n);
memset(head1,-1,sizeof(head1));cnt=0;
memset(head2,-1,sizeof(head2));
memset(head3,-1,sizeof(head3));
for(i=1;i<=n;i++){
int u,v,tem;
scanf("%d:%d",&u,&v);
s[2*i-1]=u*60+v;
scanf("%d:%d",&u,&v);
t[2*i]=u*60+v;
scanf("%d",&tem);
t[2*i-1]=s[2*i-1]+tem;
s[2*i]=t[2*i]-tem;
}
for(i=1;i<=n;i++){
for(j=i+1;j<=n;j++){
if(ok(2*i,2*j)){
addedge(2*i,2*j-1,head1);
addedge(2*j,2*i-1,head1);
}
if(ok(2*i-1,2*j)){
addedge(2*i-1,2*j-1,head1);
addedge(2*j,2*i,head1);
}
if(ok(2*i,2*j-1)){
addedge(2*i,2*j,head1);
addedge(2*j-1,2*i-1,head1);
}
if(ok(2*i-1,2*j-1)){
addedge(2*i-1,2*j,head1);
addedge(2*j-1,2*i,head1);
}
}
}
scc=0;
for(i=1;i<=2*n;i++)
if(!dfn[i])
tarjan(i);
if(!check()){
printf("NO\n");
}
else{
printf("YES\n");
make_graph();
topo();
colour();
printf_path();
}
}
本文详细阐述了2-SAT问题的求解算法,并通过实例代码展示了如何运用结构化方法解决此类问题,包括建立图模型、进行拓扑排序、着色等步骤。
257

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



