考研路茫茫——空调教室【 HDU - 2242】(求将割边去除后两连通块的最小数量差)

题目大意:给定一张图,输出将一条割边去掉后,两个连通块的值得差得最小值,如果没有割边,输出"impossible"
解题:遍历图求割边的同时记录以 u 为起点的未遍历过的路线的值的总和 all[u]. 当遇到割边时就求一次答案,取最小值。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define me(a, x) memset(a, x, sizeof a);
using namespace std;

const int N = 10010, M = 40040;

int n, m;
int h[N], e[M], ne[M], idx;
int low[N], dfn[N], timestamp;
int num[N], sum, ans;

void add(int a, int b)
{
    
    
	e[idx] = b; ne[idx] = h[a]; h[a] = idx ++; 
}

void tarjan(int u, int fa)
{
    
    
	dfn[u] = low[u] = ++ timestamp;
	bool flag = true;
	for(int i = h[u]; ~i; i = ne[i])
	{
    
    
		int j = e[i];
		if(j == fa && flag) {
    
    
			flag = false;
			continue;
		}//防止有重边
		
		if(!dfn[j])
		{
    
    
			tarjan(j, u);
			num[u] += num[j];
			low[u] = min(low[u], low[j]);
			if(low[j] > dfn[u]) ans = min(ans, abs(sum - num[j] - num[j]));
		}
		else low[u] = min(low[u], dfn[j]);
	}
}

int main()
{
    
    
	while(~scanf("%d%d", &n, &m))
	{
    
    
		me(h, -1); me(dfn, 0);
		idx = timestamp = sum = 0;
		ans = 0x3f3f3f3f;
		
		for(int i = 0; i < n; i ++ )
		{
    
    
		    scanf("%d", &num[i]);
		    sum += num[i];
		}
		
		for(int i = 0; i < m; i ++ )
		{
    
    
			int a, b;
			scanf("%d%d", &a, &b);
			add(a, b), add(b, a); 
		}
		
		tarjan(0, -1);
		
		if(ans != 0x3f3f3f3f) printf("%d\n", ans);
		else printf("impossible\n");
	}
}

猜你喜欢

转载自blog.csdn.net/qq_45904666/article/details/105098646
今日推荐