2sat专题解题报告

Bomb Game

 HDU - 3622 

题目大意:给出了n对坐标,每一对坐标选出一个放置炸弹,炸弹的半径可以控制,但是不能有相交的情况。求最大半径。

解题思路:二分+2sat   二分半径,用2sat判断当前情况是否回出现矛盾。出现矛盾的情况即一个集合里的两个元素同时被选择。

构图:添加对称边.

枚举

#include<iostream>
#include<cstdio>
#include<cmath>
#include<stack>
#include<cstring>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define N 220

int X[N],Y[N];

struct node
{
    int to,nt;
}g[N*N*2];
int n;
int tot,top;
int s[N];
int head[N],mark[N];
void addedg(int x,int y)
{
    g[tot].to=y;
    g[tot].nt=head[x];
    head[x]=tot++;
}

void init()
{
    tot=0,top=0;
    memset(head,-1,sizeof(head));
    memset(mark,false,sizeof(mark));
}

double dist(int i,int j)
{
    double dx=(X[i]-X[j])*(X[i]-X[j])*1.0;
    double dy=(Y[i]-Y[j])*(Y[i]-Y[j])*1.0;
    return sqrt(dx+dy);
}

void creat(double m)
{
    for(int i=0;i<2*n;i++)
    {
        for(int j=i+1;j<2*n;j++)
        {
            if((i>>1)!=(j>>1))
            {
                if(dist(i,j)<m*2)
                {
                    addedg(i,j^1);
                    addedg(j,i^1);
                }
            }
        }
    }
}

bool dfs(int u)
{
    if(mark[u^1])return false;
    if(mark[u]) return true;
    mark[u]=true;
    s[++top]=u;
    for(int i=head[u];i+1;i=g[i].nt)
    {
        int v=g[i].to;
        if(!dfs(v))return false;
    }
    return true;
}

bool check( )
{
    memset(mark,false,sizeof(mark));
    for(int i=0;i<2*n;i+=2)
    {
        if(!mark[i]&&!mark[i+1])
        {
            top=0;
            if(!dfs(i))
            {
                while(top)mark[s[top--]]=false;
                if(!dfs(i+1)) return false;
            }
        }
    }
    return true;
}

int main()
{
    while(scanf("%d",&n)!=EOF){
    rep(i,0,2*n-1)scanf("%d%d",&X[i],&Y[i]);
    double l=0;
    double r=9999999;
    while(r-l>=1e-6)
    {
        double m=(l+r)*0.5;
        init();
        creat(m);
        if(check( ))l=m;
        else r=m;
    }
    printf("%.2f\n",r);
    }
    return 0;
}

缩点

#include<iostream>
#include<cstdio>
#include<cmath>
#include<stack>
#include<cstring>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define N 220

int X[N],Y[N];

struct node
{
    int to,nt;
}g[N*N*2];
int n;
int tot,top;
int s[N];
int head[N],mark[N];
int bel[N],df[N];
int cnt,clo;
stack<int>S;
void addedg(int x,int y)
{
    g[tot].to=y;
    g[tot].nt=head[x];
    head[x]=tot++;
}

void init()
{
    tot=0,top=0;
    cnt=0,clo=0;
    memset(bel,0,sizeof(bel));
    memset(df,0,sizeof(df));
    memset(head,-1,sizeof(head));
    memset(mark,false,sizeof(mark));
}

double dist(int i,int j)
{
    double dx=(X[i]-X[j])*(X[i]-X[j])*1.0;
    double dy=(Y[i]-Y[j])*(Y[i]-Y[j])*1.0;
    return sqrt(dx+dy);
}

void creat(double m)
{
    for(int i=0;i<2*n;i++)
    {
        for(int j=0;j<2*n;j++)
        {
            if((i>>1)!=(j>>1))
            {
                if(dist(i,j)<m*2)
                {
                    addedg(i,j^1);
                    addedg(j,i^1);
                }
            }
        }
    }
}

int  tarjan(int u)
{
    int lowu=df[u]=++clo;
    S.push(u);
    for(int i=head[u];i+1;i=g[i].nt)
    {
        int to=g[i].to;
        if(!df[to])
        {
            int lowv=tarjan(to);
            lowu=min(lowu,lowv);
        }
        else if(!bel[to])lowu=min(lowu,df[to]);
    }
    if(df[u]==lowu)
    {
        cnt++;
        int tmp;
        do
        {
            tmp=S.top(),S.pop();
            bel[tmp]=cnt;
        }while(tmp!=u);
    }
    return lowu;
}

bool check( )
{
    for(int i=0;i<2*n;i++)
    {
        if(!df[i])tarjan(i);
    }
    for(int i=0;i<2*n;i+=2)
    {
        if(bel[i]==bel[i+1])return false;
    }
    return true;
}

int main()
{
    while(scanf("%d",&n)!=EOF){
    rep(i,0,2*n-1)scanf("%d%d",&X[i],&Y[i]);
    double l=0;
    double r=9999999;
    while(r-l>=1e-6)
    {
        double m=(l+r)*0.5;
        init();
        creat(m);
        if(check( ))l=m;
        else r=m;
    }
    printf("%.2f\n",r);
    }
}

2.

Peaceful Commission

 HDU - 1814 

解题思路:输出字典序最小的解。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<stack>
#include<cstring>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define N 20000

int X[N],Y[N];

struct node
{
    int to,nt;
}g[N*20];
int n;
int tot,top;
int s[N];
int head[N],mark[N];
void addedg(int x,int y)
{
    g[tot].to=y;
    g[tot].nt=head[x];
    head[x]=tot++;
}

void init()
{
    tot=0,top=0;
    memset(head,-1,sizeof(head));
    memset(mark,false,sizeof(mark));
}

bool dfs(int u)
{
    if(mark[u^1])return false;
    if(mark[u]) return true;
    mark[u]=true;
    s[++top]=u;
    for(int i=head[u];i+1;i=g[i].nt)
    {
        int v=g[i].to;
        if(!dfs(v))return false;
    }
    return true;
}

bool check( )
{
    for(int i=0;i<2*n;i+=2)
    {
        if(!mark[i]&&!mark[i+1])
        {
            top=0;
            if(!dfs(i))
            {
                while(top)mark[s[top--]]=false;
                if(!dfs(i+1)) return false;
            }
        }
    }
    return true;
}

int main()
{
    int m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        rep(i,1,m)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            x--;
            y--;
            addedg(x,y^1);
            addedg(y,x^1);
        }
        if(check())
        {
            for(int i=0;i<2*n;i++)
            {
                if(mark[i])printf("%d\n",i+1);
            }
        }else puts("NIE");
    }
}

Ikki's Story IV - Panda's Trick

 POJ - 3207 

题目大意:给出了一些曲线,要么从圆外连,要么从圆内连,问这些曲线会不会相交。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<stack>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define pb(x) push_back(x)
#define N 10000


struct node
{
    int x,y;
}a[N];
vector<int>G[N];
int cnt,clo;
int df[N],bel[N];
stack<int>S;
void addedg(int x,int v1,int y,int v2)
{
    x=x*2+v1;
    y=y*2+v2;
    G[x^1].pb(y);
    G[y^1].pb(x);
}

bool ok(int i,int j)
{
    if(a[i].y>a[j].x&&a[i].y<a[j].y&&a[i].x<a[j].x)return true;
    if(a[i].x>a[j].x&&a[i].x<a[j].y&&a[i].y>a[j].y)return true;
    return false;
}

int dfs(int u)
{
    int lowu=df[u]=++clo;
    S.push(u);
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        if(!df[v])
        {
            int lowv=dfs(v);
            lowu=min(lowu,lowv);
        }
        else if(!bel[v])lowu=min(lowu,df[v]);
    }
    if(lowu==df[u])
    {
        cnt++;
        int tmp;
        do
        {
            tmp=S.top(),S.pop();
            bel[tmp]=cnt;
        }while(tmp!=u);
    }
    return lowu;
}
bool solve(int m)
{
    for(int i=0;i<2*m;i++)if(!df[i])dfs(i);
    for(int i=0;i<2*m;i+=2)
    {
        if(bel[i]==bel[i+1])return false;
    }
    return true;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    rep(i,0,m-1)
    {
        scanf("%d%d",&a[i].x,&a[i].y);
        if(a[i].x>a[i].y)swap(a[i].x,a[i].y);
    }
    for(int i=0;i<m;i++)
    {
        for(int j=i+1;j<m;j++)
        {
            if(ok(i,j))
            {
                addedg(i,1,j,1);
                addedg(i,0,j,0);
            }
        }
    }
    if(solve(m))puts("panda is telling the truth...");
    else puts("the evil panda is lying again");
}
/*
7 4
1 2
6 3
7 4
5 1
*/
#include<iostream>
#include<cstdio>
#include<cmath>
#include<stack>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define pb(x) push_back(x)
#define N 10000


struct node
{
    int x,y;
}a[N];
vector<int>G[N];
int cnt,clo;
int df[N],bel[N];
stack<int>S;
void addedg(int x,int y)
{
    G[x].pb(y);
    G[y^1].pb(x^1);
}

bool ok(int i,int j)
{
    if(a[i].y>a[j].x&&a[i].y<a[j].y&&a[i].x<a[j].x)return true;
    if(a[i].x>a[j].x&&a[i].x<a[j].y&&a[i].y>a[j].y)return true;
    return false;
}

int dfs(int u)
{
    int lowu=df[u]=++clo;
    S.push(u);
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        if(!df[v])
        {
            int lowv=dfs(v);
            lowu=min(lowu,lowv);
        }
        else if(!bel[v])lowu=min(lowu,df[v]);
    }
    if(lowu==df[u])
    {
        cnt++;
        int tmp;
        do
        {
            tmp=S.top(),S.pop();
            bel[tmp]=cnt;
        }while(tmp!=u);
    }
    return lowu;
}
bool solve(int m)
{
    for(int i=0;i<2*m;i++)if(!df[i])dfs(i);
    for(int i=0;i<2*m;i+=2)
    {
        if(bel[i]==bel[i+1])return false;
    }
    return true;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    rep(i,0,m-1)
    {
        scanf("%d%d",&a[i].x,&a[i].y);
        if(a[i].x>a[i].y)swap(a[i].x,a[i].y);
    }
    for(int i=0;i<m;i++)
    {
        for(int j=i+1;j<m;j++)
        {
            if(ok(i,j))
            {
                addedg(2*i,2*j+1);
                addedg(2*i+1,2*j);
            }
        }
    }
    if(solve(m))puts("panda is telling the truth...");
    else puts("the evil panda is lying again");
}
/*
7 4
1 2
6 3
7 4
5 1
*/

Map Labeler

 POJ - 2296 

要求一些矩形不能相交,判断比较麻烦。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<stack>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define pb(x) push_back(x)
#define N 2000


struct node
{
    int x,y;
}a[N];

vector<int>G[N];
int cnt,clo;
int df[N],bel[N];
stack<int>S;
void addedg(int x,int y)
{
    G[x].pb(y);
    G[y^1].pb(x^1);
}

void init(int n)
{
    cnt=0,clo=0;
    memset(df,0,sizeof(df));
    memset(bel,0,sizeof(bel));
    for(int i=0;i<2*n;i++)G[i].clear();
}
//2*i up 2*i+1 down
void ok(int i,int j,int m)
{
    if(abs(a[i].x-a[j].x)<m)
    {
        if(abs(a[i].y-a[j].y)<m)
        {
            if(a[i].y==a[j].y)     //两者不同即可
            {
                addedg(i*2,j*2+1);
                addedg(i*2+1,j*2);
            }
            else if(a[i].y>a[j].y) //i必选上,j必选下。
            {
                G[2*i+1].pb(2*i);
                G[2*j].pb(2*j+1);
            }
            else                   //i必选下,j必选上
            {
                G[2*i].pb(2*i+1);
                G[2*j+1].pb(2*j);
            }
        }
        else if(abs(a[i].y-a[j].y)<2*m) 
        {
            if(a[i].y>a[j].y)
            {
                addedg(2*i+1,2*j+1);
            }
            else addedg(2*i,2*j);
        }
    }
}

int dfs(int u)
{
    int lowu=df[u]=++clo;
    S.push(u);
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        if(!df[v])
        {
            int lowv=dfs(v);
            lowu=min(lowu,lowv);
        }
        else if(!bel[v])lowu=min(lowu,df[v]);
    }
    if(lowu==df[u])
    {
        cnt++;
        int tmp;
        do
        {
            tmp=S.top(),S.pop();
            bel[tmp]=cnt;
        }while(tmp!=u);
    }
    return lowu;
}
bool solve(int m)
{
    for(int i=0;i<2*m;i++)if(!df[i])dfs(i);
    for(int i=0;i<2*m;i+=2)
    {
        if(bel[i]==bel[i+1])return false;
    }
    return true;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        rep(i,0,n-1)
        {
            scanf("%d%d",&a[i].x,&a[i].y);
        }
        int l=0;
        int r=50000;
        while(l<=r)
        {
            int m=(l+r)>>1;
            init(n);
            for(int i=0;i<n;i++){
                for(int j=i+1;j<n;j++){
                    ok(i,j,m);
                }
            }
            if(solve(n))l=m+1;
            else r=m-1;
            //cout<<l<<" "<<r<<endl;
        }
        printf("%d\n",r);
    }
}

Wedding

 POJ - 3648 

有坑见注释。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define pb(x) push_back(x)
#define N 1000
int n,m;

vector<int>G[N];
int mark[N];
int top;
int s[N];

void init()
{
    memset(mark,false,sizeof(mark));
    top=0;
    for(int i=0;i<4*n;i++)G[i].clear();
}

char s1[8],s2[8];

void addedg(int x,int y)
{
    G[x].pb(y);
    G[y^1].pb(x^1);
}

int get_id(char *p)
{
    int len=strlen(p);
    int sum=0;
    for(int i=0;i<len-1;i++)sum=sum*10+p[i]-'0';
    if(p[len-1]=='h')return sum*2+1;
    else return sum*2;
}

void input( )
{
    int x,y;
    G[0].pb(1);
    for(int i=1;i<=m;i++)
    {
        scanf("%s%s",s1,s2);
        x=get_id(s1);
        y=get_id(s2);
        addedg(x,y^1);
    }
}

bool dfs(int u)
{
    if(mark[u^1])return false;
    if(mark[u])return true;
    mark[u]=true;
    s[++top]=u;
    for(int i=0;i<G[u].size();i++)
    {
        if(!dfs(G[u][i]))return false;
    }
    return true;
}

bool  solve()
{
    if(!dfs(1))return false;//因为新娘那一侧可能会有矛盾,2-sat解决的是没有矛盾的一侧
    for(int i=2;i<n*2;i++)//因为要保证新娘对面没有矛盾,所以新郎是必选的。
    {
        if(!mark[2*i]&&!mark[2*i+1])
        {
            top=0;
            if(!dfs(2*i))
            {
                while(top)mark[s[top--]]=false;
                if(!dfs(2*i+1)) return false;
            }
        }
    }
    return true;
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)break;
        init();
        input();
        if(solve())
        {
            for(int i=1;i<n;i++)
            {
                printf("%d",i);
                if(mark[i*2])printf("h");
                else printf("w");
                if(i==n-1)printf("\n");
                else printf(" ");
            }
        }else puts("bad luck");
    }
}

Katu Puzzle

 POJ - 3678 

给出了一些表达式,求满足条件的值。

逗号写成分号了。。。wa了一下午。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define pb(x) push_back(x)
#define N 2005
int n,m;

struct node
{
    int to,nt;
}g[5000005];
int tot;
int head[N];

void addedg(int x,int y)
{
    g[tot].to=y;
    g[tot].nt=head[x];
    head[x]=tot++;
}

void input()
{
    int a,b,c;
    char s[8];
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d%s",&a,&b,&c,s);
        if(s[0]=='A')
        {
            if(c==1)addedg(2*a+1,2*a),addedg(2*b+1,2*b);
            else addedg(2*a,2*b+1),addedg(2*b,2*a+1);
        }
        else if(s[0]=='O')
        {
            if(c==1)addedg(2*a+1,2*b),addedg(2*b+1,2*a);
            else addedg(2*a,2*a+1),addedg(2*b,2*b+1);
        }
        else if(s[0]=='X')
        {
            if(c==1)addedg(2*a,2*b+1),addedg(2*b,2*a+1),addedg(2*a+1,2*b),addedg(2*b+1,2*a);
            else  addedg(2*a,2*b),addedg(2*b+1,2*a+1),addedg(2*a+1,2*b+1),addedg(2*b,2*a);
        }
    }
}


int df[N],bel[N];
int top,clo,cnt;
int s[N];

int dfs(int u)
{
    int lowu=df[u]=++clo;
    s[++top]=u;
    for(int i=head[u];i+1;i=g[i].nt)
    {
        int v=g[i].to;
        if(!df[v])
        {
            int lowv=dfs(v);
            lowu=min(lowu,lowv);
        }
        else if(!bel[v]) lowu=min(lowu,df[v]);
    }
    if(lowu==df[u])
    {
        cnt++;
        int tmp;
        do
        {
            tmp=s[top--];
            bel[tmp]=cnt;
        }while(tmp!=u);
    }
    return lowu;
}
bool  solve()
{
    for(int i=0;i<2*n;i++)if(!df[i])dfs(i);
    for(int i=0;i<2*n;i+=2)
    {
        if(bel[i]==bel[i+1])return false;
    }
    return true;
}

int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    input();
    if(solve())puts("YES");
    else puts("NO");
}

Eliminate the Conflict

 HDU - 4115 

题目大意:两个人石头剪刀布,男孩每局出的已知,女孩每次只能赢或者平局。然后给了一些限制条件,第a局和第b局女孩必须出的一样或者必须不一样。

解题思路:因为男孩的固定之后,女孩每局只有两个选择,可以转化为2sat。然后就是注意建图的时候。

比如第a局和第b局分别是

1 3

2 3

要求第a局和第b局不相等,此时如果我们判断不相等的话就会出错,比如1 2 不相等我们连一条1-2的边,因为要连对称边所以我们还要连一条3-3的边。。。此时就出错了。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<stack>
#include<map>
#include<vector>
#include<cstring>
#include<algorithm>
#include<string>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define pb(x) push_back(x)
#define sca(x) scanf("%d",&x)
#define LL long long
#define N 20005

int n,m;
vector<int>G[N];
int a[N];
int b[N][3];
void addedg(int x,int y)
{
    G[x].pb(y);
    G[y^1].pb(x^1);
}

int mark[N];
int s[N];
int top;
bool  dfs(int u)
{
    if(mark[u^1])return false;
    if(mark[u])return true;
    mark[u]=1;
    s[++top]=u;
    for(int i=0; i<G[u].size(); i++)
    {
        if(!dfs(G[u][i]))return false;
    }
    return true;
}
bool  solve()
{
    memset(mark,false,sizeof(mark));
    for(int i=0; i<2*n; i+=2)
    {
        if(!mark[i]&&!mark[i+1])
        {
            top=0;
            if(!dfs(i))
            {
                while(top)mark[s[top--]]=false;
                if(!dfs(i+1))return false;
            }
        }
    }
    return true;
}
int main()
{
    int t;
    scanf("%d",&t);
    int cas=1;
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0; i<n*2; i++)G[i].clear();
        rep(i,0,n-1)sca(a[i]);
        rep(i,0,n-1)
        {
            b[i][0]=a[i];
            b[i][1]=(a[i]+1)%3;
            if(b[i][1]==0)b[i][1]=3;
        }
        int x,y,z;
        rep(i,1,m)
        {
            sca(x),sca(y),sca(z);
            x--,y--;
            if(z)
            {
                for(int j=0; j<2; j++)
                {
                    for(int k=0; k<2; k++)
                    {
                        if(b[x][j]==b[y][k])
                        {
                            addedg(x*2+j,(y*2+k)^1);
                        }
                    }
                }
            }
            else
            {
                for(int j=0; j<2; j++)
                {
                    for(int k=0; k<2; k++)
                    {
                        if(b[x][j]!=b[y][k])
                        {
                            addedg(x*2+j,(y*2+k)^1);
                        }
                    }
                }
            }

        }
        printf("Case #%d: ",cas++);
        if(solve())puts("yes");
        else puts("no");
    }
}

Priest John's Busiest Day

 POJ - 3683 

题目大意:n对新人结婚要求结婚的时间段不能相交,输出可行解。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define LL long long
#define N 5005

int a[N];
int b[N*2][2];

struct node
{
    int to,nt;
}g[N*N];
int tot;
int head[N];

void addedg(int x,int y)
{
    g[tot].to=y;
    g[tot].nt=head[x];
    head[x]=tot++;
}

bool judge(int x,int y)
{
    if(b[y][0]>=b[x][0]&&b[y][0]<b[x][1])return true;
    if(b[x][0]>=b[y][0]&&b[x][0]<b[y][1])return true;
    return false;
}

void creat(int n)
{
    for(int i=0;i<n*2;i++)
    {
        for(int j=i+1;j<n*2;j++)
        {
            if((i>>1)!=(j>>1))
            {
                if(judge(i,j))
                {
                    addedg(i,j^1);
                    addedg(j,i^1);
                }
            }
        }
    }
}
int s[N],top;
int mark[N];

bool dfs(int u)
{
    if(mark[u^1])return false;
    if(mark[u])return true;
    mark[u]=1;
    s[++top]=u;
    for(int i=head[u];i+1;i=g[i].nt)
    {
        int to=g[i].to;
        if(!dfs(to))return false;
    }
    return true;
}

bool solve(int n)
{
    for(int i=0;i<2*n;i+=2)
    {
        if(!mark[i]&&!mark[i+1])
        {
            top=0;
            if(!dfs(i))
            {
                while(top)mark[s[top--]]=false;
                if(!dfs(i+1))return false;
            }
        }
    }
    return true;
}

int main()
{
    int n;
    scanf("%d",&n);
    memset(head,-1,sizeof(head));
    int h1,f1,h2,f2;
    int now=0;
    for(int i=0;i<n;i++)
    {
        scanf("%d:%d",&h1,&f1);
        scanf("%d:%d",&h2,&f2);
        scanf("%d",&a[i]);
        b[now][0]=h1*60+f1;
        b[now++][1]=h1*60+f1+a[i];
        b[now][0]=h2*60+f2-a[i];
        b[now++][1]=h2*60+f2;
    }
    creat(n);
    if(!solve(n))puts("NO");
    else
    {
        puts("YES");
        for(int i=0;i<2*n;i+=2)
        {
            if(mark[i])
            {
                printf("%02d:%02d ",b[i][0]/60,b[i][0]%60);
                printf("%02d:%02d\n",(b[i][0]+a[i/2])/60,(b[i][0]+a[i/2])%60);
            }
            else
            {
                printf("%02d:%02d ",(b[i+1][1]-a[i/2])/60,(b[i+1][1]-a[i/2])%60);
                printf("%02d:%02d\n",(b[i+1][1])/60,(b[i+1][1])%60);
            }
        }
    }
}
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define LL long long
#define N 5005

int a[N];
int b[N*2][2];

struct node
{
    int to,nt;
}g[N*N];
int tot;
int head[N];

void addedg(int x,int y)
{
    g[tot].to=y;
    g[tot].nt=head[x];
    head[x]=tot++;
}

bool judge(int x,int y)
{
    if(b[y][0]>=b[x][0]&&b[y][0]<b[x][1])return true;
    if(b[x][0]>=b[y][0]&&b[x][0]<b[y][1])return true;
    return false;
}

void creat(int n)
{
    for(int i=0;i<n*2;i++)
    {
        for(int j=i+1;j<n*2;j++)
        {
            if((i>>1)!=(j>>1))
            {
                if(judge(i,j))
                {
                    addedg(i,j^1);
                    addedg(j,i^1);
                }
            }
        }
    }
}

int df[N],clock;
int cnt,top;
int s[N],in[N];
int col[N],op[N];
int ou[N],bel[N];
int dfs(int u)
{
    int lowu=df[u]=++clock;
    s[++top]=u;

    for(int i=head[u];i+1;i=g[i].nt)
    {
        int v=g[i].to;
        if(!df[v])
        {
            int lowv=dfs(v);
            lowu=min(lowu,lowv);
        }
        else if(!bel[v])lowu=min(lowu,df[v]);
    }
    if(lowu==df[u])
    {
        cnt++;
        int tmp;
        do
        {
            tmp=s[top--];
            bel[tmp]=cnt;
        }while(tmp!=u);
    }
    return lowu;
}

void topsort(int n)
{
    queue<int>q;
    for(int i=1;i<=n;i++){
        if(in[i]==0)q.push(i);
    }

    int now=0;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        ou[++now]=u;
        for(int i=head[u];i+1;i=g[i].nt)
        {
            int v=g[i].to;
            in[v]--;
            if(in[v]==0)q.push(v);
        }
    }
}
void  go(int u)
{
    col[u]=2;
    for(int i=head[u];i+1;i=g[i].nt)
    {
        if(col[u]==0)go(g[i].to);
    }
}

bool solve(int n)
{
    for(int i=0;i<2*n;i++){
        if(!df[i])dfs(i);
    }
    for(int i=0;i<2*n;i+=2)
    {
        if(bel[i]==bel[i+1])return false;
    }

    tot=0;
    memset(head,-1,sizeof(head));
    for(int i=0;i<2*n;i++)
    {
        for(int j=head[i];j+1;j=g[j].nt)
        {
            int to=g[j].to;
            if(bel[i]!=bel[to])
            {
                addedg(bel[to],bel[i]);
                in[bel[i]]++;
            }
        }
    }
    topsort(cnt);
    for(int i=0;i<2*n;i+=2)
    {
        op[bel[i]]=bel[i+1];
        op[bel[i+1]]=bel[i];
    }
    for(int i=1;i<=cnt;i++)
    {
        int u=ou[i];
        if(col[u])continue;
        col[u]=1;
        go(op[u]);
    }
    return true;

}

int main()
{
    int n;
    scanf("%d",&n);
    memset(head,-1,sizeof(head));
    int h1,f1,h2,f2;
    int now=0;
    for(int i=0;i<n;i++)
    {
        scanf("%d:%d",&h1,&f1);
        scanf("%d:%d",&h2,&f2);
        scanf("%d",&a[i]);
        b[now][0]=h1*60+f1;
        b[now++][1]=h1*60+f1+a[i];
        b[now][0]=h2*60+f2-a[i];
        b[now++][1]=h2*60+f2;
    }
    creat(n);
    if(!solve(n))puts("NO");
    else
    {
        puts("YES");
        for(int i=0;i<2*n;i+=2)
        {
            if(col[bel[i]]==1)
            {
                printf("%02d:%02d ",b[i][0]/60,b[i][0]%60);
                printf("%02d:%02d\n",(b[i][0]+a[i/2])/60,(b[i][0]+a[i/2])%60);
            }
            else
            {
                printf("%02d:%02d ",(b[i+1][1]-a[i/2])/60,(b[i+1][1]-a[i/2])%60);
                printf("%02d:%02d\n",(b[i+1][1])/60,(b[i+1][1])%60);
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_40894017/article/details/88390673