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;
    }
    
  • 相关阅读:
    FastAPI项目实战: 个人博客项目的API
    Jmeter分布式执行,java.rmi.UnmarshalException: xxxAbstractSimpleThreadGroup错误
    [转]JMeter分布式的坑
    Docker菜鸟教程-硬敲系列
    VMware EXIS 安装
    2020简单总结
    07.1 迭代器、生成器
    locust 的 ‘1’ 版本时代变化
    移动端专项测试-内存泄漏
    乘风破浪的不止姐姐,还有我们的测试工程师!
  • 原文地址:https://www.cnblogs.com/FormerAutumn/p/9615452.html
Copyright © 2011-2022 走看看