第一次试手,就知道求割边,结果各种TLE,还改了向量为邻接表。其实问题是没有想到缩点之后是一棵树,之后每条树边都是割边,一遍dfs.
/* *State: HDU2242 281MS 1604K 2899 B *题目大意: * 给一个有重边的无向图,然后要求判断能否删除一条边使图分为 * 两个部分。图中每个点都有权重,如果可以分成两个部分,求这 * 两个部分差值的最小值。 *解题思路: * 先用tarjan缩点,把强连通分量都缩成点,因为强连通分量是不能 * 删除一条边使图分开的。缩点之后就是一棵树,之后在这棵树上进行 * 记忆化搜索。dfs一遍O(n)即可搜出结果。 *解题感想: * 原来TLE了两次,一开始以为是vector超时了,后来才发觉自己没有 * 缩点,而是求割边之后暴力,肯定TLE,当当初始化vst就够呛了。 * 之后看了别人的思路,原来缩点之后就是树,树就简单了,一遍O(n) * 的dfs就出结果。还有注意求割边的时候,要注意是否有重边,有重边 * 就稍微用flag标志下id就行啦,灵活简单。最后还wa了一次,因为忘记 * 存在一个图就是强连通图的情况(代码忘记)。 */

1 //求二次优化 2 //State: 281 MS 2520 KB GNU C++ 3 //没有快 4 #include <iostream> 5 #include <vector> 6 #include <cmath> 7 #include <cstring> 8 #include <cstdio> 9 #include <vector> 10 using namespace std; 11 12 const int MAXN = 10005; 13 const int MAXE = 20005; 14 typedef struct _node 15 { 16 int v, next; 17 }N; 18 N edge[3 * MAXE]; 19 int weight[MAXN], dfn[MAXN], low[MAXN]; 20 int step, tol, Min, half, head[MAXN], cntEdge; 21 int myS[MAXN], top, scc, id[MAXN], idw[MAXN], vst[MAXN]; 22 int dp[MAXN]; 23 //建树 24 vector<int> vec[MAXN]; 25 26 void init() 27 { 28 scc = 1; 29 Min = INT_MAX; 30 step = tol = half = top = cntEdge = 0; 31 for(int i = 0; i < MAXN; i++) 32 { 33 vst[i] = dp[i] = idw[i] = 0; 34 vec[i].clear(); 35 id[i] = -1; 36 head[i] = -1; 37 dfn[i] = low[i] = -1; 38 } 39 } 40 41 //题目好像没有提到重边 42 void addEdge(int u, int v) 43 { 44 edge[cntEdge].v = v; 45 edge[cntEdge].next = head[u]; 46 head[u] = cntEdge++; 47 48 edge[cntEdge].v = u; 49 edge[cntEdge].next = head[v]; 50 head[v] = cntEdge++; 51 } 52 53 void tarjan_scc(int n, int father) 54 { 55 dfn[n] = low[n] = ++step; 56 myS[top++] = n; 57 int flag = 0; 58 for(int f = head[n]; f != -1; f = edge[f].next) 59 { 60 int son = edge[f].v; 61 if(son == father && !flag) 62 { 63 flag = 1; 64 continue; 65 } 66 if(dfn[son] == -1) 67 { 68 tarjan_scc(son, n); 69 low[n] = min(low[n], low[son]); 70 } 71 else 72 low[n] = min(low[n], dfn[son]); 73 } 74 75 if(low[n] == dfn[n]) 76 { 77 int tmp, flag = 0; 78 do 79 { 80 tmp = myS[--top]; 81 id[tmp] = scc; 82 idw[scc] += weight[tmp]; 83 84 }while(top != 0 && tmp != n); 85 scc++; 86 } 87 } 88 89 void bulid_tree(int n) 90 { 91 for(int i = 0; i < n; i++) 92 { 93 for(int f = head[i]; f != -1; f = edge[f].next) 94 { 95 int u = i, v = edge[f].v; 96 if(id[u] == id[v]) 97 continue; 98 else 99 { 100 vec[id[u]].push_back(id[v]); 101 vec[id[v]].push_back(id[u]); 102 } 103 } 104 } 105 } 106 107 int dfs_tree(int n) 108 { 109 vst[n] = 1; 110 int tmp = idw[n]; 111 for(unsigned i = 0; i < vec[n].size(); i++) 112 { 113 int son = vec[n][i]; 114 if(!vst[son]) 115 tmp += dfs_tree(son); 116 } 117 dp[n] = tmp; 118 half = tol - dp[n]; 119 if(abs(half - dp[n]) < Min) 120 Min = abs(half - dp[n]); 121 return dp[n]; 122 } 123 124 int main(void) 125 { 126 #ifndef ONLINE_JUDGE 127 freopen("in.txt", "r", stdin); 128 #endif 129 130 int n, m; 131 while(scanf("%d %d", &n, &m) == 2) 132 { 133 init(); 134 for(int i = 0; i < n; i++) 135 { 136 scanf("%d", &weight[i]); 137 tol += weight[i]; 138 } 139 int u, v; 140 for(int i = 0; i < m; i++) 141 { 142 scanf("%d %d", &u, &v); 143 addEdge(u, v); 144 } 145 146 tarjan_scc(0, 0); 147 148 bulid_tree(n); 149 150 dfs_tree(1); 151 152 if(scc > 2) 153 printf("%d\n", Min); 154 else 155 printf("impossible\n"); 156 //cout << "********" << endl; 157 } 158 return 0; 159 }