POJ3683Priest John's Busiest Day(2sat)

POJ 2-sat六题之三

http://blog.sina.com.cn/s/blog_64675f540100k1cd.html

题目描述:有n个婚礼,每个婚礼有起始时间si,结束时间ti,还有一个主持时间ti,ti必须安排在婚礼的开始或者结束,主持由祭祀来做,但是只有一个祭祀,所以各个婚礼的主持时间不能重复,问你有没有可能正常的安排主持时间,不能输出no,能的话要输出具体的答案:即每个婚礼的主持时间段是什么样的。

解题报告:

对于每个婚礼,主持时间只有两种状态,而且各个婚礼之间的主持时间之间有相互限制,所以想到2-sat。

构图:

对于婚礼i和婚礼j。i表示在开始主持,i2表示在结束主持,j类似。

枚举每一对不同的i和j。

如果i和j冲突。连接i j2

如果i和j2冲突,连接i j

如果i2和j冲突,连接i2 j2

如果i2和j2冲突,连接i2 j

// File Name: 3683.cpp
// Author: zlbing
// Created Time: 2013/1/30 13:43:55

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
using namespace std;
#define MAXN 1050

int T[MAXN][3];
struct TwoSAT{
    int n;
    vector<int>G[MAXN*2];
    bool mark[MAXN*2];
    stack<int>S;
    bool dfs(int x)
    {
        if(mark[x^1])return false;
        if(mark[x])return true;
        mark[x]=true;
        S.push(x);
        for(int i=0;i<G[x].size();i++)
        {
            int v=G[x][i];
            if(!dfs(v))return false;
        }
        return true;
    }
    void init(int _n)
    {
        n=_n;
        for(int i=0;i<2*n;i++)
            G[i].clear();
        memset(mark,0,sizeof(mark));
    }
/*    void add_clause(int x,int xval,int y,int yval)
    {
        x=x*2+xval;
        y=y*2+yval;
        G[x^1].push_back(y);
        G[y^1].push_back(x);
    }
*/
    void add_clause(int x,int y)
    {
        G[x].push_back(y);
    }
    bool solve()
    {
        for(int i=0;i<2*n;i=i+2)
        {
            if(!mark[i]&&!mark[i+1]){
                  while(!S.empty())
                  {
                      S.pop();
                  }
                if(!dfs(i))
                {
                    while(!S.empty())
                    {
                        mark[S.top()]=false;
                        S.pop();
                    }
                    if(!dfs(i+1))return false;
                }
            }
        }
        printf("YES\n");
        int e;
        for(int i=0;i<2*n;i++)
            if(mark[i]){
                int j=T[i/2][i%2];
                if(i%2)e=-T[i/2][2];
                else e=T[i/2][2];
                if(i&1)
                printf("%02d:%02d %02d:%02d\n",(j+e)/60,(j+e)%60,j/60,j%60);
                else 
                printf("%02d:%02d %02d:%02d\n",j/60,j%60,(j+e)/60,(j+e)%60);
            }
        return true;
    }
};
TwoSAT solver;
int main(){
    int n;
    while(~scanf("%d",&n))
    {
        solver.init(n);
        for(int i=0;i<n;i++)
        {
            int a,b;
            scanf("%d:%d",&a,&b);
            a=a*60+b;
            int c,d;
            scanf("%d:%d",&c,&d);
            c=c*60+d;
            int e;
            scanf("%d",&e);
            T[i][0]=a,T[i][1]=c,T[i][2]=e;
        }
        for(int i=0;i<n;i++)
            for(int j=i+1;j<n;j++)
            {
                if(i==j)continue;
                if(T[j][0]+T[j][2]>T[i][0]&&T[i][0]+T[i][2]>T[j][0])
                         solver.add_clause(i*2,2*j+1);
                if(T[j][1]>T[i][0]&&T[i][0]+T[i][2]>T[j][1]-T[j][2])
                    solver.add_clause(i*2,2*j);
                if(T[j][0]+T[j][2]>T[i][1]-T[i][2]&&T[i][1]>T[j][0])
                    solver.add_clause(i*2+1,2*j+1);
                if(T[j][1]>T[i][1]-T[i][2]&&T[i][1]>T[j][1]-T[j][2])
                    solver.add_clause(i*2+1,2*j);
            }
        if(!solver.solve())
            printf("NO\n");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/arbitrary/p/2883829.html