您的位置:首页 > 其它

hdu 2242 考研路茫茫——空调教室

2012-10-19 13:17 323 查看
考研路茫茫——空调教室

非常好的一个题。这个题目与hdu 3298很相似,都是求分成两个连通块之后,差值最小。不过这个题目的难点在于给的不是一棵树,而是一个图有回路存在。由于只能切断一条边,所以这条边对于这个图来说,一定是割边。那么问题就变得容易的多了,枚举每条割边,算出割边去除后两个连通分量的权值和之差。如何快速计算出每个连通块的权值和。我们可以在找割边的时候,就算出每个点的子节点的权值和,注意对双连通块的处理。这里如果搜到祖先节点,那么权值就需要相加,否则累加,然后传给父亲借点。有很多人是先求出割边,然后缩点,这样就构成一颗树不过那样太麻烦了。。。

/*
*author    : cuschenan
*prog      : hdu2242
*algorithm : 无向图求割边+TREE DP 对图进行DFS,
*            在DFS的时候找割边,同时计算出每个点的子节点的个数
*            然后对于割边计算出差值。
*            这个题首先要是的不连通,我们可以很容易的想到找割边,但是要求
*            去掉某条边后,差值最小,我们就可以考虑将在同一个双连通分量中的
*            点进行缩点,然后重构成树,保留下来的边,很明显就是图的割边,我们
*            没必要去重新构图,只需要在找到割边的时候进行计算,重新构图后还是对
*            割边进行计算。只不过需要将孩子节点的个数传递过来。注意数组稍微开大一点
*2012-09-14 00:29:58	Accepted	2242	93MS	1028K	1852 B	C++	csu_chenan
*/
#include <cstdio>
#include <cstring>
#define maxn 10005
int num[maxn] ;
int first[maxn] ;
int next[maxn<<2] ;
int u[maxn<<2] ;
int dfn[maxn] ;
int low[maxn] ;
int col[maxn] ;

int depth ;
int n , m ;
int sum   ;
int ans   ;
void add_edge(int p , int q , int e){
next[e] = first[p] ;
first[p] = e ;
u[e] = q ;
}
inline void init(){
memset(dfn , 0 , sizeof(int)*n) ;
memset(low , 0 , sizeof(int)*n) ;
memset(next , -1 , sizeof(int) * 2 * m) ;
memset(col  , 0  , sizeof(int) * n ) ;
memset(first, -1 , sizeof(int) * n);
}
bool read(){
if(scanf("%d%d" , &n , &m) == EOF)
return 0 ;
sum = 0 ;
for(int i = 0 ; i < n ; i ++){
scanf("%d" , &num[i]) ;
sum += num[i] ;
}
int p , q ;
init() ;
int e = 1 ;
for(int i = 1 ; i <= m ; i ++){
scanf("%d%d" , &p , &q) ;
add_edge(p , q , e ++) ;
add_edge(q , p , e ++) ;
}
return 1 ;
}
inline int min(int x , int y){
return x < y ? x : y ;
}
int dfs(int v , int f){
int cnt , tmp ;
depth ++ ;
low[v] = depth ;
dfn[v] = depth ;
col[v] = 1 ;
cnt = num[v] ;
int flag = 0 ;
int dpv  = 0x3f3f3f3f ;
for(int i = first[v] ; i != -1 ; i = next[i]){
int x = u[i] ;

if(x == f && !flag){
flag = 1 ;
continue ;
}

if(col[x] == 1){
low[v] = min(low[v] , dfn[x]) ;
}
if(col[x] == 0){
tmp = dfs(x , v) ;
cnt += tmp ;
low[v] = min(low[v] , low[x]) ;
if(low[x] > dfn[v]){
int c = sum - tmp * 2 ;
c = c > 0 ? c : -c ;
dpv = min(dpv , c) ;
}
}
}
ans = min(ans , dpv) ;
col[v] = 2 ;
return cnt ;
}
void solve(){
depth = 0 ;
ans = 0x3f3f3f3f ;
dfs(0 , -1) ;
if(ans < 0x3f3f3f3f)
printf("%d\n" , ans) ;
else{
puts("impossible") ;
}
}
int main(){
while(read()){
solve() ;
}
return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: