zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    away3d 4.1 alpha 教程 换装篇 <3> 人物动态换装DEMO
    书本资料汇总
    洪小瑶学IOS(一):准备起航 <ObjectiveC基础教程>笔记
    Flex 4 权威指南 学习笔记
    通过存储过程建立灵活的SQL计划任务
    javascript 未结束的字符串常量
    SQL重复记录查询
    重置数据库自增字段
    C#获取周一、周日的日期 函数类
    C# ,ASP.NET,Winform将数据导出到Execl汇总
  • 原文地址:https://www.cnblogs.com/FormerAutumn/p/9615452.html
Copyright © 2011-2022 走看看