• 连通分量___刷题记录


    hdu 1269

    判断是否存在一个强连通

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<algorithm>
     5 #include<stack>
     6 #include<vector>
     7 using namespace std;
     8 
     9 const int maxn = 10005;
    10 vector<int> g[maxn];
    11 stack<int> S;
    12 
    13 int n,m;
    14 int sccno[maxn],low[maxn],pre[maxn];
    15 int scc_cnt,dfs_clock;
    16 
    17 void init(){
    18     while(!S.empty()) S.pop();
    19     for(int i = 1;i <= n;i++) g[i].clear();
    20     scc_cnt = dfs_clock = 0;
    21     memset(sccno,0,sizeof(sccno));
    22     memset(low,0,sizeof(low));
    23     memset(pre,0,sizeof(pre));
    24 }
    25 
    26 void dfs(int u){
    27     low[u] = pre[u] = ++dfs_clock;
    28     S.push(u);
    29     for(int i = 0;i < g[u].size();i++){
    30         int v = g[u][i];
    31         if(!pre[v]){
    32             dfs(v);
    33             low[u] = min(low[v],low[u]);
    34         }
    35         else if(!sccno[v]) low[u] = min(low[u],pre[v]);
    36     }
    37     if(low[u] == pre[u]){
    38         scc_cnt++;
    39         for(;;){
    40             int x = S.top();S.pop();
    41             sccno[x] = scc_cnt;
    42             if(x == u) break;
    43         }
    44     }
    45 }
    46 
    47 void find_scc(){
    48     for(int i = 1;i <= n;i++){
    49         if(!pre[i]) dfs(i);
    50     }
    51     if(scc_cnt == 1) printf("Yes
    ");
    52     else printf("No
    ");
    53 }
    54 
    55 int main(){
    56     while(scanf("%d %d",&n,&m) != EOF && (n ||m)){
    57         init();
    58         for(int i = 0;i < m;i++){
    59             int u,v;
    60             scanf("%d %d",&u,&v);
    61             g[u].push_back(v);
    62         }
    63         find_scc();
    64     }
    65     return 0;
    66 }
    View Code

    la 4287

    白书上的例题

    给一张图,问最少需要添加多少条边变成强连通

    先求一遍强连通,然后把每一个强连通分量缩成一个点,再扫一遍边,如果发现一条边的两端u,v属于不同的强连通分量,如果是u--->v,那么in[scc[v]]++,out[scc[u]++;

    最后统计入度为0的强连通分量个数a,出度为0的b,max(a,b)即为添加的最少边数

    因为对于一个强连通,每一个点的入度至少为1.出度也至少为1,添加max(a,b)条边,能够满足这个条件

    ----不知道为什么用vector存图写的wa了,换成邻接表就过了

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<iostream>
      4 #include<algorithm>
      5 #include<stack>
      6 using namespace std;
      7 
      8 const int maxn = 20005;
      9 int first[maxn];
     10 int low[maxn],pre[maxn],sc[maxn];
     11 int din[maxn],dout[maxn];
     12 int n,m;
     13 int ecnt,scnt,dfs_clock;
     14 stack<int> S;
     15 
     16 struct Edge{
     17     int v,next;
     18 }e[3*maxn];
     19 
     20 void init(){
     21     ecnt = 0;
     22     memset(first,-1,sizeof(first));
     23     memset(din,0,sizeof(din));
     24     memset(dout,0,sizeof(dout));
     25 }
     26 
     27 void addedges(int u,int v){
     28     e[ecnt].v = v;
     29     e[ecnt].next = first[u];
     30     first[u] = ecnt++;
     31 }
     32 
     33 void dfs(int u){
     34     low[u] = pre[u] = ++dfs_clock;
     35     S.push(u);
     36     for(int i = first[u];~i;i = e[i].next){
     37         int v = e[i].v;
     38         if(!pre[v]){
     39             dfs(v);
     40             low[u] = min(low[u],low[v]);
     41         }
     42         else if(!sc[v]) low[u] = min(low[u],pre[v]);
     43     }
     44     if(pre[u] == low[u]){
     45         scnt++;
     46         for(;;){
     47             int x = S.top();S.pop();
     48             sc[x] = scnt;
     49             if(x == u) break;
     50         }
     51     }
     52 }
     53 
     54 void find_scc(){
     55     while(!S.empty()) S.pop();
     56     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
     57     memset(sc,0,sizeof(sc));
     58     dfs_clock = scnt = 0;
     59     for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i);
     60 }
     61 
     62 int main(){
     63     int T;
     64     scanf("%d",&T);
     65     while(T--){
     66         scanf("%d %d",&n,&m);
     67         init();
     68         for(int i = 1;i <= m;i++){
     69             int u,v;
     70             scanf("%d %d",&u,&v);
     71             addedges(u,v);
     72         }
     73         find_scc();
     74         if(scnt == 1){
     75             printf("0
    ");
     76             continue;
     77         }
     78         for(int u = 1;u <= n;u++){
     79             for(int i = first[u];~i;i = e[i].next){
     80                 int v = e[i].v;
     81                 if(sc[u] != sc[v]){
     82                     din[sc[v]]++;
     83                     dout[sc[u]]++;
     84                 }
     85             }
     86         }
     87         
     88     //    printf("scnt = %d
    ",scnt);
     89     //    for(int i = 1;i <= scnt;i++)
     90     //    printf("din[%d] = %d  dout[%d] = %d
    ",i,din[i],i,dout[i]);
     91         
     92         int a = 0,b = 0;
     93         for(int i = 1;i <= scnt;i++){
     94             if(din[i] == 0) a++;
     95             if(dout[i] == 0) b++;
     96         }
     97         printf("%d
    ",max(a,b));
     98     }
     99     return 0;
    100 }
    View Code

    uva 11324

    先求一遍强连通,再缩点,每个点的权值为这个强连通分量里面的节点个数,就可以转化成DAG上的动态规划来做了

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<iostream>
      4 #include<algorithm>
      5 #include<stack>
      6 #include<vector>
      7 using namespace std;
      8 
      9 const int maxn = 5005;
     10 int n,m;
     11 int first[maxn];
     12 int sc[maxn],scn[maxn],low[maxn],pre[maxn];
     13 int scnt,ecnt,dfs_clock;
     14 int dp[maxn];
     15 
     16 int first1[maxn];
     17 int ecnt1;
     18 
     19 struct Edge{
     20     int v,next;
     21 }e[maxn*10];
     22 
     23 Edge e1[maxn*10];
     24 
     25 stack<int> S;
     26 
     27 void init(){
     28     ecnt = ecnt1 = 0;
     29     memset(first,-1,sizeof(first));
     30     memset(first1,-1,sizeof(first1));
     31     memset(dp,0,sizeof(dp));
     32 }
     33 
     34 void addedges(int u,int v){
     35     e[ecnt].v = v;
     36     e[ecnt].next = first[u];
     37     first[u] = ecnt++;
     38 }
     39 
     40 void addedges1(int u,int v){
     41     e1[ecnt1].v = v;
     42     e1[ecnt1].next = first1[u];
     43     first1[u] = ecnt1++;
     44 }
     45 
     46 void dfs(int u){
     47     low[u] = pre[u] = ++dfs_clock;
     48     S.push(u);
     49     for(int i = first[u];~i;i = e[i].next){
     50         int v = e[i].v;
     51         if(!pre[v]){
     52             dfs(v);
     53             low[u] = min(low[u],low[v]);
     54         }
     55         else if(!sc[v]) low[u] = min(low[u],pre[v]);
     56     }
     57     if(pre[u] == low[u]){
     58         scnt++;
     59         for(;;){
     60             int x = S.top();S.pop();
     61             sc[x] = scnt;
     62             scn[scnt]++;
     63             if(x == u) break;
     64         }
     65     }
     66 }
     67 
     68 void find_scc(){
     69     while(!S.empty()) S.pop();
     70     scnt = dfs_clock = 0;
     71     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
     72     memset(sc,0,sizeof(sc));memset(scn,0,sizeof(scn));
     73     
     74     for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i);
     75 }
     76 
     77 int solve(int p){
     78     if(dp[p]) return dp[p];
     79     for(int i = first1[p];~i;i = e1[i].next){
     80         int v = e1[i].v;
     81         dp[p] = max(dp[p],solve(v));
     82     }
     83     return dp[p] = dp[p] + scn[p];
     84 }
     85 
     86 
     87 int main(){
     88     int T;
     89     scanf("%d",&T);
     90     while(T--){
     91         init();
     92         scanf("%d %d",&n,&m);
     93         for(int i = 0;i < m;i++ ){
     94             int u,v;
     95             scanf("%d %d",&u,&v);
     96             addedges(u,v);
     97         }
     98         find_scc();
     99         
    100         for(int u = 1;u <= n;u++){
    101             for(int i = first[u];~i;i = e[i].next){
    102                 int v = e[i].v;
    103                 if(sc[u] != sc[v]) addedges1(sc[u],sc[v]);
    104             }
    105         }
    106         
    107 
    108         int ans = 0;
    109         for(int i = 1;i <= scnt;i++) ans = max(ans,solve(i));
    110         printf("%d
    ",ans);
    111     }
    112     return 0;
    113 }
    View Code

    poj 1236

    和 la 4287一样,再多一个问题,就是输出入度为0的强连通分量有多少个

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<algorithm>
     5 #include<stack>
     6 using namespace std;
     7 
     8 const int maxn = 1005;
     9 int n;
    10 stack<int> S;
    11 
    12 int first[maxn];
    13 int low[maxn],pre[maxn],sc[maxn];
    14 int scnt,ecnt,dfs_clock;
    15 int din[maxn],dout[maxn];
    16 
    17 struct Edge{
    18     int v,next;
    19 }e[maxn*50];
    20 
    21 void init(){
    22     ecnt = 0;
    23     memset(first,-1,sizeof(first));
    24     memset(din,0,sizeof(din));
    25     memset(dout,0,sizeof(dout));
    26 }
    27 
    28 void addedges(int u,int v){
    29     e[ecnt].v = v;
    30     e[ecnt].next = first[u];
    31     first[u] = ecnt++;
    32 }
    33 
    34 void dfs(int u){
    35     low[u] = pre[u] = ++dfs_clock;
    36     S.push(u);
    37     for(int i = first[u];~i;i = e[i].next){
    38         int v = e[i].v;
    39         if(!pre[v]){
    40             dfs(v);
    41             low[u] = min(low[u],low[v]);
    42         }
    43         else if(!sc[v]) low[u] = min(low[u],pre[v]);
    44     }
    45     
    46     if(pre[u] == low[u]){
    47         scnt++;
    48         for(;;){
    49             int x = S.top();S.pop();
    50             sc[x] = scnt;
    51             if(x == u) break;
    52         }
    53     }
    54 }
    55 
    56 void find_scc(){
    57     scnt = dfs_clock = 0;
    58     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
    59     memset(sc,0,sizeof(sc));
    60     for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i);
    61 }
    62 int main(){
    63     while(scanf("%d",&n) != EOF){
    64         init();
    65         for(int i = 1;i <= n;i++){
    66             int a;
    67             while(scanf("%d",&a) != EOF && a){
    68                 addedges(i,a);
    69             }
    70         }
    71         find_scc();
    72         if(scnt == 1){
    73             printf("1
    0
    ");
    74             continue;
    75         }
    76         
    77         for(int u = 1;u <= n;u++){
    78             for(int i = first[u];~i;i = e[i].next){
    79                 int v = e[i].v;
    80                 if(sc[u] != sc[v]){
    81                     din[sc[v]]++;
    82                     dout[sc[u]]++;
    83                 }
    84             }
    85         }
    86         
    87         int c1 = 0,c2 = 0;
    88         for(int i = 1;i <= scnt;i++){
    89             if(din[i] == 0) c1++;
    90             if(dout[i] == 0) c2++;
    91         }
    92         printf("%d
    %d
    ",c1,max(c1,c2));
    93     }
    94     return 0;
    95 }
    View Code

     zoj 2588

    无向图求桥,注意一下重边

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<algorithm>
     5 #include<stack>
     6 using namespace std;
     7 
     8 const int maxn = 50005;
     9 int n,m;
    10 int first[maxn];
    11 int low[maxn],pre[maxn],ans[maxn];
    12 
    13 int ecnt,cnt,dfs_clock;
    14 
    15 struct Edge{
    16     int v,next,id;
    17     int tag;
    18 }e[maxn*10];
    19 
    20 void init(){
    21     ecnt = cnt = dfs_clock = 0;
    22     memset(first,-1,sizeof(first));
    23     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
    24     memset(ans,0,sizeof(ans));
    25 }
    26 
    27 void addedges(int u,int v,int id){
    28     int i;
    29     for( i = first[u];~i;i = e[i].next){
    30         if(e[i].v == v) break;
    31     }
    32     if(i != -1){
    33         e[i].tag = 1;//如果存边的时候发现有重边,则这条边不会成为桥,标记出来,不用再储存这条边 
    34         return;
    35     }
    36     e[ecnt].tag = 0;
    37     e[ecnt].v = v;
    38     e[ecnt].next = first[u];
    39     e[ecnt].id = id;
    40     first[u] = ecnt++;
    41 }
    42 
    43 void tarjan(int u,int fa){
    44     low[u] = pre[u] = ++dfs_clock;
    45     for(int i = first[u];~i;i = e[i].next){
    46         int v = e[i].v;
    47         if(v == fa) continue;
    48         if(!pre[v]){
    49             tarjan(v,u);
    50             low[u] = min(low[u],low[v]); 
    51             if(low[v] > pre[u] && e[i].tag == 0){
    52                 ans[cnt++] = e[i].id;
    53             }
    54         }
    55         else low[u] = min(low[u],pre[v]);
    56     }
    57 } 
    58 
    59 int main(){
    60     int T;
    61     scanf("%d",&T);
    62     while(T--){
    63         init();
    64         scanf("%d %d",&n,&m);
    65         for(int i = 1;i <= m;i++){
    66             int u,v;
    67             scanf("%d %d",&u,&v);
    68             addedges(u,v,i);addedges(v,u,i);
    69         }
    70         tarjan(1,0);
    71         printf("%d
    ",cnt);
    72         if(cnt){
    73             sort(ans,ans+cnt);
    74             printf("%d",ans[0]);
    75             for(int i = 1;i < cnt;i++) printf(" %d",ans[i]);
    76             printf("
    ");
    77         }
    78         if(T) printf("
    ");
    79     }
    80     return 0;
    81 }
    View Code

    poj 3352  边双连通

    给定一张无向图,使得删掉任意一条边之后,整张图还是连通的至少需要添加多少条边

    先用tarjan()求一下每个节点的low,用low的值来缩点,因为在同一个连通分量上的节点的low值都是相同的,

    无向图的度数的定义是,这个节点连有几条边,它的度数就是几

    然后再扫一遍边,如果这条边的两端的low值不同,则d[low[v]]++,d[low[u]]不用++,因为是无向图,在存边的时候就正向反向的边都存了

    所以只需要加一个

    然后求出度数为1的块有ans个

    那么加(ans+1)/2条边就可以了

    是因为将度数为1的块两两连接起来,即为(ans+1)/2

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<algorithm>
     5 #include<vector>
     6 using namespace std;
     7 
     8 const int maxn = 1005;
     9 int n,m;
    10 int d[maxn];
    11 int low[maxn],pre[maxn];
    12 int first[maxn];
    13 int ecnt,dfs_clock;
    14 
    15 struct Edge{
    16     int v,next;
    17 }e[10*maxn];
    18 
    19 void init(){
    20     ecnt = dfs_clock = 0;
    21     memset(first,-1,sizeof(first));
    22     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
    23     memset(d,0,sizeof(d));
    24 }
    25 
    26 void addedges(int u,int v){
    27     e[ecnt].v = v;
    28     e[ecnt].next = first[u];
    29     first[u] = ecnt++;
    30 }
    31 
    32 void tarjan(int u,int fa){
    33     low[u] = pre[u] = ++dfs_clock;
    34     for(int i = first[u];~i;i = e[i].next){
    35         int v = e[i].v;
    36         if(v == fa) continue;
    37         if(!pre[v]){
    38             tarjan(v,u);
    39             low[u] = min(low[u],low[v]);
    40         }
    41         else if(v != fa) low[u] = min(low[u],pre[v]);
    42     }
    43 }
    44 
    45 int main(){
    46     while(scanf("%d %d",&n,&m) != EOF){
    47         init();
    48         for(int i = 1;i <= m;i++){
    49             int u,v;
    50             scanf("%d %d",&u,&v);
    51             addedges(u,v);addedges(v,u);
    52         }
    53         tarjan(1,-1);
    54         
    55     //    for(int i = 1;i <= n;i++)
    56     //    printf("pre[%d] = %d  low[%d] = %d
    ",i,pre[i],i,low[i]);
    57         
    58         for(int u = 1;u <= n;u++){
    59             for(int i = first[u];~i;i = e[i].next){
    60                 int v = e[i].v;
    61                 if(low[u] != low[v])    d[low[v]]++;
    62             }
    63         }
    64         
    65     //    for(int i = 1;i <= n;i++)
    66      //   printf("d[%d] = %d
    ",i,d[i]);
    67         
    68         int ans = 0;
    69         for(int i = 1;i <= n;i++) if(d[i]== 1) ans++;
    70         printf("%d
    ",(ans+1)/2);
    71     }
    72     return 0;
    73 }
    View Code

    hdu 1827

    先求一遍强连通,然后缩点

    找入度为0的点就是需要传递消息的块,找出这个块里面花费最少的,再累加起来

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<algorithm>
     5 #include<stack>
     6 using namespace std;
     7 
     8 const int maxn = 1005;
     9 const int INF = 1000000005;
    10 int first[maxn];
    11 int n,m;
    12 int scnt,dfs_clock,ecnt;
    13 int low[maxn],pre[maxn],sc[maxn];
    14 int in[maxn],a[maxn];
    15 int cost[maxn];
    16 stack<int> S;
    17 
    18 struct Edge{
    19     int v,next;
    20 }e[10*maxn];
    21 
    22 void init(){
    23     ecnt = 0;
    24     memset(first,-1,sizeof(first));
    25     memset(in,0,sizeof(in));
    26     memset(a,0,sizeof(a));
    27     for(int i = 1;i <= n;i++) cost[i] = INF;
    28 }
    29 
    30 void addedges(int u,int v){
    31     e[ecnt].v = v;
    32     e[ecnt].next = first[u];
    33     first[u] = ecnt++;
    34 }
    35 
    36 void dfs(int u){
    37     low[u] = pre[u] = ++dfs_clock;
    38     S.push(u);
    39     for(int i = first[u];~i;i = e[i].next){
    40         int v = e[i].v;
    41         if(!pre[v]){
    42             dfs(v);
    43             low[u] = min(low[u],low[v]);
    44         }
    45         else if(!sc[v]) low[u] = min(low[u],pre[v]);
    46     }
    47     if(pre[u] == low[u]){
    48         scnt++;
    49         for(;;){
    50             int x = S.top();S.pop();
    51             sc[x] = scnt;
    52             if(x == u) break;
    53         }
    54     }
    55 }
    56 
    57 void find_scc(){
    58     scnt = dfs_clock = 0;
    59     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
    60     memset(sc,0,sizeof(sc));
    61     
    62     for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i);
    63 }
    64 
    65 int main(){
    66     while(scanf("%d %d",&n,&m) != EOF){
    67         init();
    68         for(int i = 1;i <= n;i++) scanf("%d",&a[i]);
    69         for(int i = 0;i < m;i++){
    70             int u,v;
    71             scanf("%d %d",&u,&v);
    72             addedges(u,v);
    73         }
    74         find_scc();
    75         for(int u = 1;u <= n;u++){
    76             for(int i = first[u];~i;i = e[i].next){
    77                 int v = e[i].v;
    78                 if(sc[u] != sc[v]) in[sc[v]]++;
    79             }
    80         }
    81         
    82         for(int i = 1;i <= n;i++){
    83             if(in[sc[i]] == 0) cost[sc[i]] = min(cost[sc[i]],a[i]);
    84         }
    85         
    86         int ans = 0,res = 0;
    87         for(int i = 1;i <= scnt;i++){
    88             if(in[i] == 0) ans += cost[i],res++;
    89         }
    90         printf("%d %d
    ",res,ans);
    91     }
    92     return 0;
    93 }
    View Code

    hdu 3072

    给定一个定点,到其他所有点的花费最小

    先求一遍强连通,再缩点,更新不同的连通块之间的最小的花费,如果某一块的d[i] = INF,说明其他的块都不能到达它

    则说明它的入度为0,为给定的那个定点

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<algorithm>
     5 #include<stack>
     6 using namespace std;
     7 
     8 const int maxn = 50005;
     9 const int INF = 1000000005;
    10 typedef long long LL;
    11 int first[maxn];
    12 int n,m;
    13 int scnt,dfs_clock,ecnt;
    14 int low[maxn],pre[maxn],sc[maxn];
    15 int in[maxn];
    16 int d[maxn];
    17 stack<int> S;
    18 
    19 struct Edge{
    20     int v,next,w;
    21 }e[10*maxn];
    22 
    23 void init(){
    24     ecnt = 0;
    25     memset(first,-1,sizeof(first));
    26     memset(in,0,sizeof(in));
    27     for(int i = 1;i <= n;i++) d[i] = INF;
    28 }
    29 
    30 void addedges(int u,int v,int w){
    31     e[ecnt].v = v;
    32     e[ecnt].w = w;
    33     e[ecnt].next = first[u];
    34     first[u] = ecnt++;
    35 }
    36 
    37 void dfs(int u){
    38     low[u] = pre[u] = ++dfs_clock;
    39     S.push(u);
    40     for(int i = first[u];~i;i = e[i].next){
    41         int v = e[i].v;
    42         if(!pre[v]){
    43             dfs(v);
    44             low[u] = min(low[u],low[v]);
    45         }
    46         else if(!sc[v]) low[u] = min(low[u],pre[v]);
    47     }
    48     if(pre[u] == low[u]){
    49         scnt++;
    50         for(;;){
    51             int x = S.top();S.pop();
    52             sc[x] = scnt;
    53             if(x == u) break;
    54         }
    55     }
    56 }
    57 
    58 void find_scc(){
    59     scnt = dfs_clock = 0;
    60     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
    61     memset(sc,0,sizeof(sc));
    62     
    63     for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i);
    64 }
    65 
    66 int main(){
    67     while(scanf("%d %d",&n,&m) != EOF){
    68         init();
    69         for(int i = 0;i < m;i++){
    70             int u,v,w;
    71             scanf("%d %d %d",&u,&v,&w);u++;v++;
    72             addedges(u,v,w);
    73         }
    74         find_scc();
    75         for(int u = 1;u <= n;u++){
    76             for(int i = first[u];~i;i = e[i].next){
    77                 int v = e[i].v;
    78                 if(sc[u] != sc[v]) d[sc[v]] = min(d[sc[v]],e[i].w);
    79             }
    80         }
    81         
    82         LL ans = 0;
    83         for(int i = 1;i <= scnt;i++) {
    84             if(d[i] != INF) ans += d[i];
    85         }
    86         printf("%I64d
    ",ans);
    87     }
    88     return 0;
    89 }
    View Code

     poj 3114

    缩点之后,存边的时候可以贪心,维持两个连通分量间的最小距离,
    再用dijkstra,

    最开始看到n是500,兴高采烈地用floyd---t掉了----

    too--young--

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<iostream>
      4 #include<algorithm>
      5 #include<vector>
      6 #include<stack>
      7 using namespace std;
      8 
      9 const int maxn = 505;
     10 const int INF = 1000000005;
     11 int n,m,q;
     12 int first[maxn],first1[maxn];
     13 int low[maxn],pre[maxn],sc[maxn];
     14 int ecnt,ecnt1,dfs_clock,scnt;
     15 stack<int> S;
     16 
     17 int d[maxn][maxn];
     18 int vis[maxn];
     19 int dis[maxn];
     20 
     21 struct Edge{
     22     int v,next,w;
     23 };
     24 
     25 Edge e[maxn*maxn],e1[maxn*maxn];
     26 
     27 void init(){
     28     ecnt = ecnt1 = 0;
     29     memset(first,-1,sizeof(first));
     30 }
     31 
     32 void dijkstra(int s,int N){
     33     for(int i=1;i<=N;i++) dis[i]=INF,vis[i] = 0;
     34     dis[s]=0;
     35     
     36     for(int k=1;k<=N;k++){
     37         int p,m=INF;
     38         for(int i=1;i<=N;i++) if(!vis[i]&&dis[i]<m) m=dis[p=i];
     39         vis[p]=1;
     40         for(int i=1;i<=N;i++) dis[i]=min(dis[i],dis[p]+d[p][i]);
     41     }
     42 }
     43 
     44 void addedges(int u,int v,int w){
     45     e[ecnt].v = v;
     46     e[ecnt].w = w;
     47     e[ecnt].next = first[u];
     48     first[u] = ecnt++;
     49 }
     50 
     51 void tarjan(int u,int fa){
     52     low[u] = pre[u] = ++dfs_clock;
     53     S.push(u);
     54     for(int i = first[u];~i;i = e[i].next){
     55         int v = e[i].v;
     56         if(!pre[v]){
     57             tarjan(v,u);
     58             low[u] = min(low[u],low[v]);
     59         }
     60         else if(!sc[v]) low[u] = min(low[u],pre[v]);
     61     }
     62     if(low[u] == pre[u]){
     63         scnt++;
     64         for(;;){
     65             int x = S.top();S.pop();
     66             sc[x] = scnt;
     67             if(x == u) break;
     68         }
     69     }
     70 }
     71 
     72 void find_scc(){
     73     scnt = dfs_clock = 0;
     74     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
     75     memset(sc,0,sizeof(sc));
     76     while(!S.empty()) S.pop();
     77     
     78     for(int i = 1;i <= n;i++) if(!pre[i]) tarjan(i,-1);
     79 }
     80 
     81 
     82 int main(){
     83     int kase = 0;
     84     while(scanf("%d %d",&n,&m) != EOF && n){
     85         if(kase) puts("");kase++;
     86         init();
     87         for(int i = 1;i <= m;i++){
     88             int u,v,w;
     89             scanf("%d %d %d",&u,&v,&w);
     90             addedges(u,v,w);
     91         }
     92         
     93         
     94         find_scc();
     95         //扫一遍边,边的两端在同一个连通分量的,权值设为0;
     96         
     97         for(int i =1 ;i <= scnt;i++){
     98             for(int j = 1;j <= scnt;j++){
     99                 if(i != j) d[i][j] = INF;
    100                 else d[i][j] = 0;
    101             }
    102         }
    103         
    104         for(int u = 1;u <= n;u++){
    105             for(int i = first[u];~i;i = e[i].next){
    106                 int v = e[i].v;
    107                 if(sc[u] != sc[v]) d[sc[u]][sc[v]] = min(d[sc[u]][sc[v]],e[i].w);
    108                 else d[sc[u]][sc[v]] = 0;
    109             }
    110         }
    111           
    112         scanf("%d",&q);
    113         while(q--){
    114             int u,v;
    115             scanf("%d %d",&u,&v);
    116             if(sc[u] == sc[v]) puts("0");
    117             else{
    118                 dijkstra(sc[u],scnt);
    119                 if(dis[sc[v]] == INF) printf("Nao e possivel entregar a carta
    ");
    120                 else printf("%d
    ",dis[sc[v]]);
    121             }
    122         }
    123     }
    124     return 0;
    125 }
    View Code

    poj 2253

    如果一个点能够到达的其他的点也能够到达它,则把它叫做一个底,求图里面的所有的底

    缩点,统计出度为0的块,块里面的所有的点都满足

    话说数组开成5005为什么会t啊----开大点就过了----

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<algorithm>
     5 #include<stack>
     6 using namespace std;
     7 
     8 const int maxn = 20005;
     9 int n,m;
    10 int first[maxn];
    11 int low[maxn],pre[maxn],sc[maxn];
    12 int dout[maxn];
    13 int scnt,ecnt,dfs_clock;
    14 int c[maxn];
    15 stack<int> S;
    16 
    17 struct Edge{
    18     int v,next;
    19 }e[10*maxn];
    20 
    21 void init(){
    22     ecnt = 0;
    23     memset(first,-1,sizeof(first));
    24     memset(dout,0,sizeof(dout));
    25 }
    26 
    27 void addedges(int u,int v){
    28     e[ecnt].v = v;
    29     e[ecnt].next = first[u];
    30     first[u] = ecnt++;
    31 }
    32 
    33 void tarjan(int u,int fa){
    34     low[u] = pre[u] = ++dfs_clock;
    35     S.push(u);
    36     for(int i = first[u];~i;i = e[i].next){
    37         int v = e[i].v;
    38         if(!pre[v]){
    39             tarjan(v,u);
    40             low[u] = min(low[u],low[v]);
    41         }
    42         else if(!sc[v]) low[u] = min(low[u],pre[v]);
    43     }
    44     if(pre[u] == low[u]){
    45         scnt++;
    46         for(;;){
    47             int x = S.top();S.pop();
    48             sc[x] = scnt;
    49             if(x == u) break;
    50         }
    51     }
    52 }
    53 
    54 void find_scc(){
    55     while(!S.empty()) S.pop();
    56     dfs_clock = ecnt = 0;
    57     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
    58     memset(sc,0,sizeof(sc));
    59     for(int i = 1;i <= n;i++) if(!pre[i]) tarjan(i,-1);
    60 }
    61 
    62 int main(){
    63     while(scanf("%d",&n) != EOF && n){
    64         scanf("%d",&m);
    65         init();
    66         for(int i = 1;i <= m;i++){
    67             int u,v;
    68             scanf("%d %d",&u,&v); addedges(u,v);
    69         }
    70         find_scc();
    71         for(int u = 1;u <= n;u++){
    72             for(int i = first[u];~i;i = e[i].next){
    73                 int v = e[i].v;
    74                 if(sc[u] != sc[v]) dout[sc[u]]++;
    75             }
    76         }
    77         int num = 0;
    78         for(int i = 1;i <= n;i++){
    79             if(dout[sc[i]] == 0) printf("%d ",i);
    80         }
    81         printf("
    ");
    82     }
    83     return 0; 
    84 }
    View Code

    poj 2186

    求出这样的点的个数,即其他点都能够到达它的点

    先缩点,缩完点之后是一个DAG,DAG的终点(出度为0的点)就是要求的,

    如果终点有多个,则不满足了,因为缩点之后不存在环,所以终点之间的点不能到达

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<algorithm>
     5 #include<stack>
     6 using namespace std;
     7 
     8 const int maxn = 20005;
     9 int first[maxn];
    10 int low[maxn],pre[maxn],sc[maxn];
    11 int din[maxn],dout[maxn];
    12 int n,m;
    13 int ecnt,scnt,dfs_clock;
    14 stack<int> S;
    15 
    16 struct Edge{
    17     int v,next;
    18 }e[3*maxn];
    19 
    20 void init(){
    21     ecnt = 0;
    22     memset(first,-1,sizeof(first));
    23     memset(din,0,sizeof(din));
    24     memset(dout,0,sizeof(dout));
    25 }
    26 
    27 void addedges(int u,int v){
    28     e[ecnt].v = v;
    29     e[ecnt].next = first[u];
    30     first[u] = ecnt++;
    31 }
    32 
    33 void dfs(int u){
    34     low[u] = pre[u] = ++dfs_clock;
    35     S.push(u);
    36     for(int i = first[u];~i;i = e[i].next){
    37         int v = e[i].v;
    38         if(!pre[v]){
    39             dfs(v);
    40             low[u] = min(low[u],low[v]);
    41         }
    42         else if(!sc[v]) low[u] = min(low[u],pre[v]);
    43     }
    44     if(pre[u] == low[u]){
    45         scnt++;
    46         for(;;){
    47             int x = S.top();S.pop();
    48             sc[x] = scnt;
    49             if(x == u) break;
    50         }
    51     }
    52 }
    53 
    54 void find_scc(){
    55     while(!S.empty()) S.pop();
    56     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
    57     memset(sc,0,sizeof(sc));
    58     dfs_clock = scnt = 0;
    59     for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i);
    60 }
    61 
    62 int main(){
    63     while( scanf("%d %d",&n,&m) != EOF){
    64         init();
    65         for(int i = 1;i <= m;i++){
    66             int u,v;
    67             scanf("%d %d",&u,&v);
    68             addedges(u,v);
    69         }
    70         find_scc();
    71         for(int u = 1;u <= n;u++){
    72             for(int i = first[u];~i;i = e[i].next){
    73                 int v = e[i].v;
    74                 if(sc[u] != sc[v]){
    75                     dout[sc[u]]++;
    76                 }
    77             }
    78         }
    79         int c = 0;
    80         for(int i = 1;i <= scnt;i++){
    81             if(dout[i] == 0) c++;
    82         }
    83         if(c > 1) printf("0
    ");
    84         else{
    85             int res = 0;
    86             for(int i = 1;i <= n;i++){
    87                 if(dout[sc[i]] == 0) res++;
    88             }
    89             printf("%d
    ",res);
    90         }
    91     }
    92     return 0;
    93 }
    View Code
  • 相关阅读:
    Sublime Text 3 3126 注册码
    修改bootstrap 的全局样式,bootstrap 3.0 是由html5和CSS 3组成的
    mysql-sql高级应用
    MySQL 主键冲突,无法插入数据
    jquery加载页面的方法(页面加载完成就执行)
    Jquery怎么获取select选中项 自定义属性的值
    使用Yii2中dropdownlist实现地区三级联动的例子
    Yii2中省市三级联动(栏目联动)
    [HNOI2009] 梦幻布丁
    [CJOJ2410]数列操作d
  • 原文地址:https://www.cnblogs.com/wuyuewoniu/p/4688309.html
Copyright © 2020-2023  润新知