码迷,mamicode.com
首页 > 其他好文 > 详细

hdu 4738 2013杭州赛区网络赛 桥+重边+连通判断 ***

时间:2015-08-29 16:41:01      阅读:138      评论:0      收藏:0      [点我收藏+]

标签:

题意:有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("*****\n");
 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\n");
157             continue;
158         }
159         printf("%d\n",solve(n));
160     }
161     return 0;
162 }

 

hdu 4738 2013杭州赛区网络赛 桥+重边+连通判断 ***

标签:

原文地址:http://www.cnblogs.com/cnblogs321114287/p/4769179.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!