第一次试手,就知道求割边,结果各种TLE,还改了向量为邻接表。其实问题是没有想到缩点之后是一棵树,之后每条树边都是割边,一遍dfs.

/*
*State: HDU2242 281MS 1604K 2899 B
*题目大意:
*        给一个有重边的无向图,然后要求判断能否删除一条边使图分为
*        两个部分。图中每个点都有权重,如果可以分成两个部分,求这
*        两个部分差值的最小值。
*解题思路:
*        先用tarjan缩点,把强连通分量都缩成点,因为强连通分量是不能
*        删除一条边使图分开的。缩点之后就是一棵树,之后在这棵树上进行
*        记忆化搜索。dfs一遍O(n)即可搜出结果。
*解题感想:
*        原来TLE了两次,一开始以为是vector超时了,后来才发觉自己没有
*        缩点,而是求割边之后暴力,肯定TLE,当当初始化vst就够呛了。
*        之后看了别人的思路,原来缩点之后就是树,树就简单了,一遍O(n)
*        的dfs就出结果。还有注意求割边的时候,要注意是否有重边,有重边
*        就稍微用flag标志下id就行啦,灵活简单。最后还wa了一次,因为忘记
*        存在一个图就是强连通图的情况(代码忘记)。
*/
View Code
  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 }
posted on 2012-08-16 01:23  cchun  阅读(242)  评论(0编辑  收藏  举报