[2-sat]构造一个可行解(poj3648)

2-sat问题的可行解

当我们确定了存在一个可行解的时候,下面的工作往往是要构造一个可行解,那么,如何来构造这样的解呢?
我们知道,当我们选择了一个强连通分量中的一个点的时候,所有的点都会被选择,所以,此时,我们将强连通分量缩点,这样就构造出了一个有向无环图。对这个图进行反向的拓扑排序,然后进行染色就行了。
我们知道,分别含有同一个逻辑变量构造出来的两个点的强连通分量是不可以同时被选择的,使用这个规则染色,再逐个判断即可。

一个问题(poj3648)

John is the only priest in his town. September 1st is the John’s busiest day in a year because there is an old legend in the town that the couple who get married on that day will be forever blessed by the God of Love. This year N couples plan to get married on the blessed day. The i-th couple plan to hold their wedding from time Si to time Ti. According to the traditions in the town, there must be a special ceremony on which the couple stand before the priest and accept blessings. The i-th couple need Di minutes to finish this ceremony. Moreover, this ceremony must be either at the beginning or the ending of the wedding (i.e. it must be either from Si to Si + Di, or from Ti - Di to Ti). Could you tell John how to arrange his schedule so that he can present at every special ceremonies of the weddings.

Note that John can not be present at two weddings simultaneously.

这个题也是十分显然的,重要的就是构造可行解,代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<stack>
#include<queue>
#include<vector>
using namespace std;

#define MAXN 1005
#define MAXM 2005

struct Wedd{
    int st;
    int en;
    int len;
}wedList[MAXN];

struct Edge{
    int to;
    int next;
}EdgeTable[MAXM*MAXM];

int N;
int head[MAXM];
int dfn[MAXM],low[MAXM],state[MAXM];
int match[MAXM];
int cf[MAXM];
int e,cnt,curT;
stack<int>S;

void Input()
{
    int i;
    char str1[10],str2[10];

    for(i=0;i<N;i++){
        scanf("%s %s %d",str1,str2,&wedList[i].len);
        wedList[i].st = ((str1[0]-'0')*10+(str1[1]-'0'))*60+((str1[3]-'0')*10+(str1[4]-'0'));
        wedList[i].en = ((str2[0]-'0')*10+(str2[1]-'0'))*60+((str2[3]-'0')*10+(str2[4]-'0'));
    }

    return;
}

void addEdge(int from,int to)
{
    EdgeTable[e].to=to;
    EdgeTable[e].next=head[from];
    head[from]=e++;
}

void print(int num)
{
    int a=num/60;
    int b=num%60;
    char a1=(a/10)+'0',a2=(a%10)+'0';
    char b1=(b/10)+'0',b2=(b%10)+'0';
    printf("%c%c:%c%c",a1,a2,b1,b2);
    return;
}

bool Judge(int a,int aa,int b,int bb)
{
    int st1,st2,en1,en2;
    if(aa==0){
        st1=wedList[a].st;
        en1=wedList[a].st+wedList[a].len;
    }
    else{
        st1=wedList[a].en-wedList[a].len;
        en1=wedList[a].en;
    }

    if(bb==0){
        st2=wedList[b].st;
        en2=wedList[b].st+wedList[b].len;
    }
    else{
        st2=wedList[b].en-wedList[b].len;
        en2=wedList[b].en;
    }

    if(st1>=en2||en1<=st2)return true;
    else return false;
}

void get_Graph()
{
    memset(head,-1,sizeof(head));
    e=0;
    int i,j;

    for(i=0;i<N;i++){
        for(j=i+1;j<N;j++){
            if(!Judge(i,0,j,0)){
                addEdge(i*2,j*2+1);
                addEdge(j*2,i*2+1);
            }

            if(!Judge(i,1,j,0)){
                addEdge(i*2+1,j*2+1);
                addEdge(j*2,i*2);
            }

            if(!Judge(i,1,j,1)){
                addEdge(i*2+1,j*2);
                addEdge(j*2+1,i*2);
            }

            if(!Judge(i,0,j,1)){
                addEdge(i*2,j*2);
                addEdge(j*2+1,i*2+1);
            }
        }
    }
    return;
}

void TopSort()
{
    queue<int>Q;
    int indeg[MAXM];
    int vis[MAXM];
    vector<int>grid[MAXM];


    int i,j;

    memset(vis,0,sizeof(vis));
    memset(indeg,0,sizeof(indeg));

    for(i=0;i<2*N;i++){
        for(j=head[i];j!=-1;j=EdgeTable[j].next){
            if(match[i]!=match[EdgeTable[j].to]){
                indeg[match[i]]++;
                grid[match[EdgeTable[j].to]].push_back(match[i]);
            }
        }
    }

    for(i=0;i<cnt;i++){
        if(!indeg[i]){
            indeg[i]=-1;
            Q.push(i);
        }
    }

    while(!Q.empty()){
        int cur = Q.front();
        Q.pop();
        if(vis[cur]==0){
            vis[cur]=1;
            vis[cf[cur]]=-1;
        }

        for(i=0;i<grid[cur].size();i++){
            indeg[grid[cur][i]]--;
            if(!indeg[grid[cur][i]])
                Q.push(grid[cur][i]);
        }
    }

    for(i=0;i<N;i++){
        if(vis[match[2*i]]==1){
            print(wedList[i].st);
            printf(" ");
            print(wedList[i].st+wedList[i].len);
        }
        else{
            print(wedList[i].en-wedList[i].len);
            printf(" ");
            print(wedList[i].en);
        }
        printf("\n");
    }

    for(i=0;i<MAXM;i++)
        grid[i].clear();
}

void Dfs(int cur)
{
    dfn[cur]=low[cur]=curT++;
    state[cur]=1;
    S.push(cur);

    int i;
    for(i=head[cur];i!=-1;i=EdgeTable[i].next){
        int dest = EdgeTable[i].to;
        if(!state[dest]){
            Dfs(dest);
            low[cur] = min(low[cur],low[dest]);
        }
        else if(state[dest]==1)
            low[cur] = min(low[cur],low[dest]);
    }

    if(dfn[cur]==low[cur]){
        while(!S.empty()){
            int d=S.top();
            S.pop();
            match[d]=cnt;
            state[d]=2;
            if(d==cur)break;
        }
        cnt++;
    }

}

void Solve()
{
    int i;

    memset(state,0,sizeof(state));
    memset(cf,-1,sizeof(cf));
    memset(match,-1,sizeof(match));
    cnt=0;

    for(i=0;i<2*N;i++){
        if(!state[i]){
            curT=0;
            Dfs(i);
        }
    }

    for(i=0;i<N;i++){
        if(match[2*i]==match[2*i+1]){
            printf("NO\n");
            return;
        }
        //mark the tags
        //two points from the same logic variable
        //can not be chosen at the same time
        cf[match[2*i]]=match[2*i+1];
        cf[match[2*i+1]]=match[2*i];
    }
    printf("YES\n");
    TopSort();
    return;
}

int main()
{
    //freopen("input","r",stdin);
    while(scanf("%d",&N)!=EOF){
        Input();
        get_Graph();
        Solve();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值