zoukankan      html  css  js  c++  java
  • poj3683

    poj3683

    题意

    n对新人举行婚礼,婚礼在不同时间段但可能重叠,婚礼有开始(Si)、结束(Ti)、仪式举行时间(Di),问能否给出一种举行方案,使得神父能参加所有的婚礼并举行仪式。

    分析

    xi为真 <=> 在开始时举行仪式,
    xj为假 <=> 在结束时举行仪式。
    设x' 为 非x。(若 x 为真,则 x' 为假)
    xi -> xj 表示 xi 为真则 xj 为真。(xi xj 连边)

    对于结婚仪式 i 和 j ,如果 Si ~ Si+Di 和 Sj ~ Sj+Dj 冲突,就有 xi' or xj' ,这种情况即 xi -> xj' ,xj -> xi' 。(xi 和 xj 不能同时选,即选择一个,那么选了 xi 后 就会选择到 xj' ,表示不选 xj。)
    如果 Si ~ Si+Di 和 Tj-Dj ~ Dj 冲突,有 xi' or xj ,即 xi -> xj,xj' -> xi' 。
    如果 Ti-Di ~ Ti 和 Sj ~ Sj+Dj 冲突,有 xi or xj' ,即 xi' -> xj',xj -> xi 。
    如果 Ti-Di ~ Ti 和 Tj-Dj ~ Dj 冲突 ,有 xi or xj ,即 xi' -> xj ,xj' -> xi 。

    代码参照《 挑战程序设计竞赛》,网上的代码大多是按照论文进行模拟?

    书中有个步骤比较疑惑,打印可行解时,

    x 所在的强连通分量的拓扑序在 x' 所在的强连通分量之后 <=> x 为真。

    一点理解:拓扑序靠后的出度小,越不会影响后面的选择?

    code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<set>
    #include<map>
    #include<algorithm>
    typedef long long ll;
    
    using namespace std;
    
    const int MAXN = 2e3 + 10;
    int n, m; // 点、边
    int vis[MAXN];
    int flag[MAXN]; // 所属强连通分量的拓扑序
    vector<int> G[MAXN], rG[MAXN];
    vector<int> vs; // 后序遍历顺序的顶点列表
    void addedge(int x, int y)
    {
        G[x].push_back(y);  // 正向图
        rG[y].push_back(x); // 反向图
    }
    void dfs(int u)
    {
        vis[u] = 1;
        for(int i = 0; i < G[u].size(); i++)
        {
            int v = G[u][i];
            if(!vis[v]) dfs(v);
        }
        vs.push_back(u);
    }
    void rdfs(int u, int k)
    {
        vis[u] = 1;
        flag[u] = k;
        for(int i = 0; i < rG[u].size(); i++)
        {
            int v = rG[u][i];
            if(!vis[v]) rdfs(v, k);
        }
    }
    int scc() // 强连通分量的个数
    {
        vs.clear();
        memset(vis, 0, sizeof vis);
        for(int i = 1; i <= n; i++) //  [1...n]
            if(!vis[i]) dfs(i);
        memset(vis, 0, sizeof vis);
        int k = 0;
        for(int i = vs.size() - 1; i >= 0; i--)
            if(!vis[vs[i]]) rdfs(vs[i], k++);
        return k;
    }
    
    int S[MAXN], D[MAXN], T[MAXN];
    
    void solve()
    {
        int N = n;
        n = 2 * n;
        for(int i = 1; i <= n; i++)
        {
            G[i].clear();
            rG[i].clear();
        }
        for(int i = 1; i <= n; i++) // 枚举、连边
        {
            for(int j = 1; j < i; j++)
            {
                if(min(S[i] + D[i], S[j] + D[j]) > max(S[i], S[j]))
                {
                    // xi -> xj' ,xj -> xi'
                    addedge(i, j + N);
                    addedge(j, i + N);
                }
                if(min(S[i] + D[i], T[j]) > max(S[i], T[j] - D[j]))
                {
                    // xi -> xj,xj' -> xi'
                    addedge(i, j);
                    addedge(j + N, i + N);
                }
                if(min(T[i], S[j] + D[j]) > max(S[j], T[i] - D[i]))
                {
                    //  xi' -> xj',xj -> xi
                    addedge(i + N, j + N);
                    addedge(j, i);
                }
                if(min(T[i], T[j]) > max(T[i] - D[i], T[j] - D[j]))
                {
                    // xi' -> xj ,xj' -> xi
                    addedge(i + N, j);
                    addedge(j + N, i);
                }
            }
        }
        scc();
    
        // 判断可行性
        for(int i = 1; i <= N; i++)
        {
            if(flag[i] == flag[N + i])
            {
                puts("NO");
                return;
            }
        }
    
        // 输出可行解
        puts("YES");
        for(int i = 1; i <= N; i++)
        {
            if(flag[i] > flag[i + N]) // 在仪式开始时举行
                printf("%02d:%02d %02d:%02d
    ", S[i] / 60, S[i] % 60, (S[i] + D[i]) / 60, (S[i] + D[i]) % 60);
            else
                printf("%02d:%02d %02d:%02d
    ", (T[i] - D[i]) / 60, (T[i] - D[i]) % 60, T[i] / 60, T[i] % 60);
        }
    }
    
    int main()
    {
        while(~scanf("%d", &n))
        {
            for(int i = 1; i <= n; i++)
            {
                int x1, y1, x2, y2;
                char p, q;
                scanf("%02d:%02d %02d:%02d %d", &x1, &y1, &x2, &y2, &D[i]);
                S[i] = x1 * 60 + y1;
                T[i] = x2 * 60 + y2;
            }
            solve();
        }
        return 0;
    }
    
  • 相关阅读:
    【iOS】7.4 定位服务->2.1.1 定位
    【iOS】7.4 定位服务->1.0 简介
    1.2.1 OC概述
    5.1 网络基础
    4.4 多线程进阶篇<下>(NSOperation)
    4.3 多线程进阶篇<中>(GCD)
    4.1/4.2 多线程进阶篇<上>(Pthread & NSThread)
    4.0 多线程基础篇
    2.1 -1.0 Xcode(发布时间、使用、快捷键、插件相关)
    一款面试复习应用源码
  • 原文地址:https://www.cnblogs.com/ftae/p/6791279.html
Copyright © 2011-2022 走看看