zoukankan      html  css  js  c++  java
  • hdu 4738 2013杭州赛区网络赛 桥+重边+连通判断 ***

    题意:有n座岛和m条桥,每条桥上有w个兵守着,现在要派不少于守桥的士兵数的人去炸桥,只能炸一条桥,使得这n座岛不连通,求最少要派多少人去。

    处理重边

    边在遍历的时候,第一个返回的一定是之前去的边,所以这条边忽略,然后继续遍历,此时可以通过未遍历的边返回pre

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<algorithm>
      4 #include<cstring>
      5 #include<cmath>
      6 #include<queue>
      7 #include<map>
      8 using namespace std;
      9 #define MOD 1000000007
     10 const int INF=0x3f3f3f3f;
     11 const double eps=1e-5;
     12 typedef long long ll;
     13 #define cl(a) memset(a,0,sizeof(a))
     14 #define ts printf("*****
    ");
     15 int n,m,tt;
     16 /*
     17 * 求 无向图的割点和桥
     18 * 可以找出割点和桥,求删掉每个点后增加的连通块。
     19 * 需要注意重边的处理,可以先用矩阵存,再转邻接表,或者进行判重
     20 */
     21 const int MAXN = 10010;
     22 const int MAXM = 2000010;
     23 struct Edge
     24 {
     25     int to,next;
     26     int w;
     27     bool cut;//是否为桥的标记
     28 }edge[MAXM];
     29 int head[MAXN],tot;
     30 int Low[MAXN],DFN[MAXN],Stack[MAXN];
     31 int Index,top;
     32 bool Instack[MAXN];
     33 bool cut[MAXN];
     34 int add_block[MAXN];//删除一个点后增加的连通块
     35 int bridge;
     36 void addedge(int u,int v,int w)
     37 {
     38     edge[tot].to = v;edge[tot].next = head[u];edge[tot].cut = false;
     39     edge[tot].w = w;
     40     head[u] = tot++;
     41 
     42 }
     43 void Tarjan(int u,int pre)
     44 {
     45     int v;
     46     Low[u] = DFN[u] = ++Index;
     47     Stack[top++] = u;
     48     Instack[u] = true;
     49     int son = 0;
     50     int pre_num=0;
     51     for(int i = head[u];i != -1;i = edge[i].next)
     52     {
     53         v = edge[i].to;
     54         if(v == pre&&pre_num==0)
     55         {
     56             pre_num++;
     57             continue;
     58         }
     59         if( !DFN[v] )
     60         {
     61             son++;
     62             Tarjan(v,u);
     63             if(Low[u] > Low[v])Low[u] = Low[v];
     64             // 65             //一条无向边(u,v)是桥,当且仅当(u,v)为树枝边,且满足DFS(u)<Low(v)。
     66             if(Low[v] > DFN[u])
     67             {
     68                 bridge++;
     69                 edge[i].cut = true;
     70                 edge[i^1].cut = true;
     71             }
     72             //割点
     73             //一个顶点u是割点,当且仅当满足(1)或(2) (1) u为树根,且u有多于一个子树。
     74             //(2) u不为树根,且满足存在(u,v)为树枝边(或称父子边,
     75             //即u为v在搜索树中的父亲),使得DFS(u)<=Low(v)
     76             if(u != pre && Low[v] >= DFN[u])//不是树根
     77             {
     78                 cut[u] = true;
     79                 add_block[u]++;
     80             }
     81         }
     82         else if( Low[u] > DFN[v])
     83         Low[u] = DFN[v];
     84     }
     85     //树根,分支数大于1
     86     if(u == pre && son > 1)cut[u] = true;
     87     if(u == pre)add_block[u] = son - 1;
     88     Instack[u] = false;
     89     top--;
     90 }
     91 int solve(int N)
     92 {
     93     memset(DFN,0,sizeof(DFN));
     94     memset(Instack,false,sizeof(Instack));
     95     memset(add_block,0,sizeof(add_block));
     96     memset(cut,false,sizeof(cut));
     97     Index = top = 0;
     98     bridge = 0;
     99     for(int i = 1;i <= N;i++)
    100         if(!DFN[i])
    101             Tarjan(i,i);
    102     int ret=INF;
    103     for(int u = 1;u <= N;u++)
    104     for(int i = head[u];i != -1;i = edge[i].next)
    105     if(edge[i].cut)
    106     {
    107         ret=min(ret,edge[i].w);
    108     }
    109     if(ret==INF)    return -1;
    110     if(ret==0)  ret++;
    111     return ret;
    112 }
    113 int F[MAXN];
    114 int find(int x)
    115 {
    116     if(F[x] == -1)return x;
    117     else return F[x] = find(F[x]);
    118 }
    119 void init()
    120 {
    121     memset(F,-1,sizeof(F));
    122     tot = 0;
    123     memset(head,-1,sizeof(head));
    124 }
    125 void bing(int u,int v)
    126 {
    127     int t1 = find(u);
    128     int t2 = find(v);
    129     if(t1 != t2)F[t1] = t2;
    130 }
    131 int main()
    132 {
    133     int n,m;
    134     #ifndef ONLINE_JUDGE
    135     freopen("1.in","r",stdin);
    136     #endif
    137     while(scanf("%d%d",&n,&m) == 2)
    138     {
    139         if(n == 0 && m == 0)break;
    140         int u,v,w;
    141         init();
    142         while(m--)
    143         {
    144             scanf("%d%d%d",&u,&v,&w);
    145             if(u == v)continue;
    146             addedge(u,v,w);
    147             addedge(v,u,w);
    148             bing(u,v);
    149         }
    150         bool flag = true;
    151         for(int i = 1; i <= n;i++)
    152             if(find(i) != find(1))
    153                 flag = false;
    154         if(!flag)
    155         {
    156             printf("0
    ");
    157             continue;
    158         }
    159         printf("%d
    ",solve(n));
    160     }
    161     return 0;
    162 }
  • 相关阅读:
    Android虚拟、实体键盘不能同时使用?
    libwebsockets 运行问题
    Qt TabWidget QTabBar 宽高设置
    I.MX6 recovery mode hacking
    libwebsockets libwebsockets-webserver.c hacking
    MySQL(六)常用语法和数据类型
    MySQL(五)汇总和分组数据
    MySQL(四)字段及常用函数
    MySQL(三)用正则表达式搜索
    MySQL(二)数据的检索和过滤
  • 原文地址:https://www.cnblogs.com/cnblogs321114287/p/4769179.html
Copyright © 2011-2022 走看看