Graph_Master(连通分量_D_Trajan缩点+dfs)

hdu_2242

题目大意:求将一张无向图(n个点,m条边)移除一条边分为不连通两部分,使得两部分的点权和最接近,若无法分为两部分,则输出impossible。

题解:拿到题面还算清晰,就是先tarjan缩点,因为边双连通分量肯定无法移除一条边使得分为不连通的两部分(因为是无向图),然后重新建图,附好点权,就可以开始愉快地跑dfs了,然后不断比较取min即可。但是wa了将近五发之后(检查完了笔误细节),笔者不服了,这个方法肯定是没有问题的,那么问题在哪?笔者发现,这题编号竟然是从0~n-1,我真的说不出话,审题不仔细,简直写到难过,以为改了能对之后,又wa了一发,笔者静下来检查,确保无误后,又提交了一次,又wa了,于是笔者去hdu该题的discuss找到了一组样例,不得不说,wa得心服口服,因为题目输入可能有重边,即0 1 , 1 0,因为是无向图所以存边肯定调用了两次_add(u,v),所以等于0 1之间,有了四条边,如果if (v==pre) then continue,那么就会出错,这个点可以说是很坑人了,只能说是自己疏忽了,但是这个也很好解决,只要多加个flag判断就好。其实也就是两个点的边双连通要考虑。(个人觉得两个点不可能叫边双连通,暂且这样称作吧,即上文0 1 , 1 0


#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
#define mem(a,b) memset((a),(b),sizeof(a))
using namespace std;

const int N = 1e4 + 16;

struct Edge
{
	int u, v, nxt;
};
Edge edge[N<<1], edge2[N<<1];

bool vis[N];
int head[N], ecnt;
int head2[N], ecnt2;
int sta[N], dfn[N], low[N], col[N];
int val[N], vv[N], f[N];
int top, dep, sum;
int n, m;

void _add( int u, int v )
{
	edge[ecnt].u = u;
	edge[ecnt].v = v;
	edge[ecnt].nxt = head[u];
	head[u] = ecnt ++;
}

void _add2( int u, int v )
{
	edge2[ecnt2].u = u;
	edge2[ecnt2].v = v;
	edge2[ecnt2].nxt = head2[u];
	head2[u] = ecnt2 ++;
}

void init()
{
	mem(head,-1);
	mem(vis,0);
	mem(sta,0);
	mem(dfn,0);
	mem(low,0);
	mem(val,0);
	top = sum = dep = ecnt = 0;
}

void tarjan( int u, int pr )
{
	sta[++top] = u;
	low[u] = dfn[u] = ++dep;
	vis[u] = 1;
	
	int flag = 1;
	for ( int i = head[u]; i+1; i = edge[i].nxt )
	{
		int v = edge[i].v;
		if ( v == pr && flag )
		{
			flag = 0;
			continue;
		}
		
		if ( !dfn[v] )
		{
			tarjan( v, u );
			low[u] = min( low[u], low[v] );
		}
		else if ( vis[v] )
			low[u] = min( low[u], low[v] );
	}
	
	if ( low[u] == dfn[u] )
	{
		col[u] = ++sum;
		vis[u] = 0;
		while ( sta[top] != u )
		{
			col[sta[top]] = sum;
			vis[sta[top--]] = 0;
		}
		top --;
	}
}

void dfs( int u )
{
	if ( vis[u] ) return ;
	vis[u] = 1;
	f[u] += vv[u];
	
	for ( int i = head2[u]; i+1; i = edge2[i].nxt )
	{
		int v = edge2[i].v;
		if ( !vis[v] )
		{
			dfs(v);
			f[u] += f[v];
		}
	}
}

int main()
{
	while ( ~scanf("%d%d", &n, &m) )
	{
		init();
		int pow = 0;
		for ( int i = 0; i < n; i ++ )
		{
			scanf("%d", &val[i]);
			pow += val[i];
		}
		for ( int i = 0; i < m; i ++ )
		{
			int u, v;
			scanf("%d%d", &u, &v);
			_add(u,v);
			_add(v,u);
		}
		
		for ( int i = 0; i < n; i ++ )
			if ( !dfn[i] )
				tarjan(i, -1);
			
		if ( sum == 1 )
		{
			puts("impossible");
			continue;
		}
		
		mem(head2,-1);
		ecnt2 = 0;
		mem(vv,0);
		mem(f,0);
		for ( int i = 0; i < n; i ++ )
		{
			vv[col[i]] += val[i];
			for ( int j = head[i]; j+1; j = edge[j].nxt )
			{
				int v = edge[j].v;
				if ( col[i] != col[v] )
					_add2(col[i],col[v]);
			}
		}
		
		mem(vis,0);
		dfs(1);
		
		int ans = pow;
		for ( int i = 1; i <= sum; i ++ )
			ans = min( ans, abs( pow - f[i] - f[i] ) );
		
//		cout << "sum: " << sum << endl;
		printf("%d
", ans);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/FormerAutumn/p/9615452.html