【POJ3683】Priest John's Busiest Day

题目大意:给定 N 个操作,每个操作占用两个区间中的任意一个即可,求是否可以满足 N 项操作,且使得操作区间不重叠,若可以,输出一种具体方案。

题解:2-sat 模板题,区间覆盖的位置有些毒瘤,貌似题意没交代清楚?

代码如下

#include <cstdio>
#include <vector>
#include <utility>
#include <ctype.h>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) x.begin(),x.end()
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=2010;
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline ll sqr(ll x){return x*x;}
inline ll read(){
    ll x=0,f=1;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
    do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
    return f*x;
}

vector<int> G[maxn];
int dfs_clk,dfn[maxn],low[maxn],stk[maxn],in[maxn],top;
int scc,cor[maxn];
int n,st[maxn],ed[maxn],len[maxn];
char s[10];

bool overlap(int a, int b, int c, int d) {
    if (a >= c&&a<d || b>c&&b <= d || a <= c&&b >= d) return 1;
    return 0;
}

void read_and_parse(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",s+1);
        st[i]=((s[1]-'0')*10+s[2]-'0')*60+(s[4]-'0')*10+s[5]-'0';
        scanf("%s",s+1);
        ed[i]=((s[1]-'0')*10+s[2]-'0')*60+(s[4]-'0')*10+s[5]-'0';
        scanf("%d",&len[i]);
    }
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++){
            if(overlap(st[i],st[i]+len[i],st[j],st[j]+len[j]))G[i].pb(j+n),G[j].pb(i+n);
            if(overlap(st[i],st[i]+len[i],ed[j]-len[j],ed[j]))G[i].pb(j),G[j+n].pb(i+n);
            if(overlap(ed[i]-len[i],ed[i],st[j],st[j]+len[j]))G[i+n].pb(j+n),G[j].pb(i);
            if(overlap(ed[i]-len[i],ed[i],ed[j]-len[j],ed[j]))G[i+n].pb(j),G[j+n].pb(i);
        }
}

void tarjan(int u){
    low[u]=dfn[u]=++dfs_clk;
    stk[++top]=u,in[u]=1;
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i];
        if(!dfn[v])tarjan(v),low[u]=min(low[u],low[v]);
        else if(in[v])low[u]=min(dfn[v],low[u]);
    }
    if(low[u]==dfn[u]){
        ++scc;int v;
        do{
            v=stk[top--],in[v]=0;
            cor[v]=scc;
        }while(u!=v);
    }
}

void solve(){
    for(int i=1;i<=n<<1;i++)if(!dfn[i])tarjan(i);
    for(int i=1;i<=n;i++)if(cor[i]==cor[i+n])return (void)puts("NO");
    puts("YES");
    for(int i=1;i<=n;i++){
        if(cor[i]<cor[i+n])
            printf("%02d:%02d %02d:%02d\n",st[i]/60,st[i]%60,(st[i]+len[i])/60,(st[i]+len[i])%60);
        else
            printf("%02d:%02d %02d:%02d\n",(ed[i]-len[i])/60,(ed[i]-len[i])%60,ed[i]/60,ed[i]%60);
    }
}

int main(){
    read_and_parse();
    solve();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/wzj-xhjbk/p/10633170.html