zoukankan      html  css  js  c++  java
  • poj 3683(2-SAT+SCC)

    传送门:Problem 3683

     https://www.cnblogs.com/violet-acmer/p/9769406.html

    参考资料:

      [1]:挑战程序设计竞赛

    题意:

      有n场婚礼,每场婚礼有起始时间si,结束时间ti,还有一个主持仪式需要花费ti时间,ti必须安排在婚礼的开始或者结束。

      主持由神父来做,但是只有一个神父,所以各个婚礼的主持时间不能重复,不过神父可以在出席完一个主持仪式后,立刻出席另一个开始时间与其结束时间相等的主持仪式,问你有没有可能正常的安排主持时间,不能输出no,能的话要输出具体的答案:即每个婚礼的主持时间在那个时间段。

    题解:

      对于每个结婚仪式 i ,只有在开始或结束时进行主持仪式,两种选择,因此可定义变量 Xi;

          Xi 为真 <=> 在开始时进行主持仪式

      这样,对于婚礼 i 和 j ,如果Si~Si+Di 和 Sj~Sj+Dj 冲突,就有子句 (非Xi V 非Xj) 为真,对于开始和开始,开始和结束,结束和开始,结束和结束分别对应四条子句,也可得到类似的条件。

      于是,要保证所有主持仪式的时间不冲突,只要考虑将这些所有的子句用 ^(合取)连接起来所得道德布尔公式就好了。

      例如,对于输入的样例可以得到的布尔公式为:

                                                

      而当x1为真而x2为假时,其值为真。

      这样,我们就把原问题转为了2-SAT问题,接下来只要进行强连通分量分解并判断是否有使得布尔公式值为真的一组布尔变量就好了。

      以上分析来自挑战程序设计竞赛P326。

    难点:  

      根据2-SAT建立有向图,用SCC分解强连通分量

    AC代码:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<vector>
      4 #include<cstring>
      5 #include<cmath>
      6 using namespace std;
      7 #define mem(a,b) (memset(a,b,sizeof a))
      8 #define pb push_back
      9 const int maxn=1e3+50;
     10 
     11 //X1~Xn : 1~n
     12 //非X1~非Xn : n+1~2*n
     13 int n;
     14 int s[maxn];
     15 int t[maxn];
     16 int d[maxn];
     17 vector<int >G[2*maxn],rG[2*maxn];//注意此处是 2*maxn
     18 vector<int >vs;
     19 int scc[2*maxn];
     20 bool vis[2*maxn];
     21 void addEdge(int u,int v)
     22 {
     23     G[u].pb(v);
     24     rG[v].pb(u);
     25 }
     26 void SAT()
     27 {
     28     for(int i=1;i <= n;++i)
     29     {
     30         for(int j=1;j < i;++j)
     31         {
     32             if(max(s[i],s[j]) < min(s[j]+d[j],s[i]+d[i]))//第 i 场婚礼的开始时主持时间与第 j 场婚礼的开始时主持时间冲突
     33                 addEdge(i,j+n),addEdge(j,i+n);
     34             if(max(s[i],t[j]-d[j]) < min(t[j],s[i]+d[i]))//第 i 场婚礼的开始时主持时间与第 j 场婚礼的结束时主持时间冲突
     35                 addEdge(i,j),addEdge(j+n,i+n);//注意,第二处是 j+n -> i+n
     36             if(max(s[j],t[i]-d[i]) < min(t[i],s[j]+d[j]))//第 i 场婚礼的结束时主持时间与第 j 场婚礼的开始时主持时间冲突
     37                 addEdge(i,j),addEdge(i+n,j+n);//注意,第二处是 i+n -> j+n
     38             if(max(t[i]-d[i],t[j]-d[j]) < min(t[i],t[j]))//第 i 场婚礼的结束时主持时间与第 j 场婚礼的结束时主持时间冲突
     39                 addEdge(i+n,j),addEdge(j+n,i);
     40         }
     41     }
     42 }
     43 void Dfs(int u)
     44 {
     45     vis[u]=true;
     46     for(int i=0;i < G[u].size();++i)
     47         if(!vis[G[u][i]])
     48             Dfs(G[u][i]);
     49     vs.pb(u);
     50 }
     51 void rDfs(int u,int k)
     52 {
     53     vis[u]=true;
     54     scc[u]=k;
     55     for(int i=0;i < rG[u].size();++i)
     56     {
     57         int to=rG[u][i];
     58         if(!vis[to])
     59             rDfs(to,k);
     60     }
     61 }
     62 void SCC()
     63 {
     64     mem(vis,false);
     65     vs.clear();
     66     for(int i=1;i <= n;++i)
     67         if(!vis[i])
     68             Dfs(i);
     69     mem(vis,false);
     70     int k=0;
     71     for(int i=vs.size()-1;i >= 0;--i)
     72         if(!vis[vs[i]])
     73             rDfs(vs[i],++k);
     74 }
     75 void Init()
     76 {
     77     for(int i=0;i < maxn;++i)
     78         G[i].clear(),rG[i].clear();
     79 }
     80 int main()
     81 {
     82 
     83     while(~scanf("%d",&n))
     84     {
     85         Init();
     86         for(int i=1;i <= n;++i)
     87         {
     88             int h,m;
     89             char ch;
     90             scanf("%d%c%d",&h,&ch,&m);
     91             s[i]=h*60+m;//将开始时间转化为分钟
     92             scanf("%d%c%d",&h,&ch,&m);
     93             t[i]=h*60+m;//将结束时间转化为分钟
     94             scanf("%d",d+i);
     95         }
     96         SAT();//根据2-SAT建图
     97         SCC();//强连通分量分解
     98         bool flag=false;
     99         for(int i=1;i <= n;++i)
    100             if(scc[i] == scc[i+n])
    101                 flag=true;
    102         if(flag)
    103             printf("NO
    ");
    104         else
    105         {
    106             printf("YES
    ");
    107             for(int i=1;i <= n;++i)
    108             {
    109                 if(scc[i] > scc[i+n])
    110                     printf("%02d:%02d %02d:%02d
    ",s[i]/60,s[i]%60,(s[i]+d[i])/60,(s[i]+d[i])%60);
    111                 else
    112                     printf("%02d:%02d %02d:%02d
    ",(t[i]-d[i])/60,(t[i]-d[i])%60,t[i]/60,t[i]%60);
    113             }
    114         }
    115     }
    116     return 0;
    117 }
    View Code
  • 相关阅读:
    用c#小程序理解线程
    我对线程入门理解
    网站发布后IIS故障解决办法
    ASP .NET XML 文件
    SortedList 对象兼有 ArrayList 和 Hashtable 对象的特性。
    (笔记)索引器
    HOW TO:使用 Visual C# .NET 在 ASP.NET 中创建自定义错误报告
    读取EXCEL的数据到datagridview
    一个超级简单的文件流操作WINDOW应用程序
    Gridview事件
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/9769361.html
Copyright © 2011-2022 走看看