• 图论算法----强连通


    poj 2186 Popular Cows

    分析:直接求一下强连通分量,对于同一个强连通分量里面的结点状态是相同的,要求有多少个人被其他所有的人都认可,只有可能是拓扑排序的最后一个强连通的结点个数,判断一下其他节点是否都可以到该联通分量就ok了。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <set>
     5 #include <algorithm>
     6 #include <map>
     7 #include<vector>
     8 #define maxn 10010
     9 #define maxm 50010
    10 using namespace std;
    11 int n,m;
    12 vector<int>G[maxn];
    13 vector<int>rG[maxn];
    14 vector<int>vs;
    15 bool used[maxn];
    16 int cmp[maxn];
    17 void addedge(int u,int v){
    18     G[u].push_back(v);
    19     rG[v].push_back(u);
    20 }
    21 void init(){
    22     for(int i=0;i<=n;++i){
    23         G[i].clear();
    24         rG[i].clear();
    25     }
    26 }
    27 void dfs(int u){
    28     used[u]=true;
    29     for(int i=0;i<G[u].size();++i){
    30         if(!used[G[u][i]])dfs(G[u][i]);
    31     }
    32     vs.push_back(u);
    33 }
    34 void rdfs(int u,int k){
    35     used[u]=true;
    36     cmp[u]=k;
    37     for(int i=0;i<rG[u].size();++i){
    38         if(!used[rG[u][i]])rdfs(rG[u][i],k);
    39     }
    40 }
    41 int scc(){
    42     memset(used,0,sizeof(used));
    43     vs.clear();
    44     for(int i=0;i<n;++i){
    45         if(!used[i])dfs(i);
    46     }
    47     memset(used,0,sizeof(used));
    48     int k =0;
    49     for (int i=vs.size()-1;i>=0;--i){
    50         if(!used[vs[i]])rdfs(vs[i],k++);
    51     }
    52     return k;
    53 }
    54 void solve(){
    55     int nn = scc();
    56     int cnt =0,u=0;
    57     for(int i=0;i<n;++i){
    58         if(cmp[i]==nn-1){
    59             u = i;
    60             cnt++;
    61         }
    62     }
    63     memset(used,0,sizeof(used));
    64     rdfs(u,0);
    65     for(int i=0;i<n;++i){
    66         if(!used[i]){
    67             cnt=0;
    68             break;
    69         }
    70     }
    71     printf("%d
    ",cnt);
    72 }
    73 int main (){
    74     while(scanf("%d%d",&n,&m)!=EOF){
    75         init();
    76         int x,y;
    77         for(int i=0;i<m;++i){
    78             scanf("%d%d",&x,&y);
    79             addedge(x-1,y-1);
    80         }
    81         solve();
    82     }
    83 }
    View Code

    poj3683   Priest John's Busiest Day

    题目意思:有n个事务,每个有两种时间段选择,问你可不可以安排使得n个事务不冲突。

    分析:转成2-SAT求解,对于每一个事务,有两种选择就是是或者否,根据相应的条件完成建图后使用强连通求解2-SAT

    把第i个事务拆成两个点i i+m分别对应开始时间段与结束时间段,然后根据时间段是否有冲突写出合取范式建图求解

    对于规则a∨b 可以改写为 ┐a->b∧┐b->a 可以翻一下离散的书

    si与sj冲突那么就可以写成 ┐xi V ┐xj   转为xi->┐xj 建边(i,j+m)

    同理另外三种情况看代码

    利用强连通求解2-SAT只需要判断i结点与i+m结点是不是在一个强连通分支里面,如果在说明两者同时成立,这显然是不合理的。

    如果i结点的拓扑序在i+m前面则i成立即第i个事务选择在开始时执行否则在结束时执行

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <set>
      5 #include <algorithm>
      6 #include <map>
      7 #include<vector>
      8 #define maxn 4010
      9 #define maxm 50010
     10 using namespace std;
     11 int n,m;
     12 vector<int>G[maxn];
     13 vector<int>rG[maxn];
     14 vector<int>vs;
     15 bool used[maxn];
     16 int cmp[maxn];
     17 void addedge(int u,int v){
     18     G[u].push_back(v);
     19     rG[v].push_back(u);
     20 }
     21 void init(){
     22     for(int i=0;i<=n;++i){
     23         G[i].clear();
     24         rG[i].clear();
     25     }
     26 }
     27 void dfs(int u){
     28     used[u]=true;
     29     for(int i=0;i<G[u].size();++i){
     30         if(!used[G[u][i]])dfs(G[u][i]);
     31     }
     32     vs.push_back(u);
     33 }
     34 void rdfs(int u,int k){
     35     used[u]=true;
     36     cmp[u]=k;
     37     for(int i=0;i<rG[u].size();++i){
     38         if(!used[rG[u][i]])rdfs(rG[u][i],k);
     39     }
     40 }
     41 int scc(){
     42     memset(used,0,sizeof(used));
     43     vs.clear();
     44     for(int i=0;i<n;++i){
     45         if(!used[i])dfs(i);
     46     }
     47     memset(used,0,sizeof(used));
     48     int k =0;
     49     for (int i=vs.size()-1;i>=0;--i){
     50         if(!used[vs[i]])rdfs(vs[i],k++);
     51     }
     52     return k;
     53 }
     54 int s[maxn],t[maxn],d[maxn];
     55 void build(){
     56     for(int i=0;i<m;++i){
     57         for(int j=0;j<i;++j){
     58                 if(min(s[i]+d[i],s[j]+d[j])>max(s[i],s[j])){
     59                     //开始与开始冲突 xi->^xj&&xj->^xi
     60                     addedge(i,j+m);
     61                     addedge(j,i+m);
     62                 }
     63                 if(min(s[i]+d[i],t[j])>max(s[i],t[j]-d[j])){
     64                     //开始与结束冲突 xi->xj&&^xj->^xi
     65                     addedge(i,j);
     66                     addedge(j+m,i+m);
     67                 }
     68                 if(min(t[i],s[j]+d[j])>max(t[i]-d[i],s[j])){
     69                     //结束与开始冲突 ^xi->^xj&&xj->xi
     70                     addedge(i+m,j+m);
     71                     addedge(j,i);
     72                 }
     73                 if(min(t[i],t[j])>max(t[i]-d[i],t[j]-d[j])){
     74                     //结束与结束冲突 ^xi->xj&&^xj->xi
     75                     addedge(i+m,j);
     76                     addedge(j+m,i);
     77                 }
     78             }
     79     }
     80 }
     81 void solve(){
     82     build();
     83     int k =scc();
     84     for(int i=0;i<m;++i){
     85         if(cmp[i]==cmp[m+i]){
     86             printf("NO
    ");
     87             return ;
     88         }
     89     }
     90     printf("YES
    ");
     91     for(int i=0;i<m;++i){
     92         if(cmp[i]>cmp[i+m]){
     93             printf("%02d:%02d %02d:%02d
    ",s[i]/60,s[i]%60,(s[i]+d[i])/60,(s[i]+d[i])%60);
     94         }
     95         else printf("%02d:%02d %02d:%02d
    ",(t[i]-d[i])/60,(t[i]-d[i])%60,t[i]/60,t[i]%60);
     96     }
     97 }
     98 int main (){
     99     while(scanf("%d",&m)!=EOF){
    100         init();
    101         n = 2*m;
    102         int sh,sm,th,tm;
    103         for(int i=0;i<m;++i){
    104             scanf("%d:%d %d:%d %d",&sh,&sm,&th,&tm,&d[i]);
    105             s[i]=sh*60+sm;
    106             t[i]=th*60+tm;
    107         }
    108         solve();
    109     }
    110 }
    View Code
  • 相关阅读:
    codevs 1102 采药 2005年NOIP全国联赛普及组
    codevs 1058 合唱队形 2004年NOIP全国联赛提高组
    动归题目
    友好城市//未测,不知对错
    codevs 1044 拦截导弹 1999年NOIP全国联赛提高组
    codevs 5294 挖地雷
    codevs 1576 最长严格上升子序列
    [BZOJ3289]Mato的文件管理
    [CodeVS1299]切水果
    [TYVJ1473]校门外的树3
  • 原文地址:https://www.cnblogs.com/shuzy/p/3775661.html
Copyright © 2020-2023  润新知