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("*****\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 }