• HDU3488 Tour KM


    原文链接http://www.cnblogs.com/zhouzhendong/p/8284304.html


    题目传送门 - HDU3488


    题意概括

      给一个n的点m条边的有向图。

      然后让你把这个图分成许多环,问环中边权和最小为多少。

      题目保证一定存在合法的方案。


    题解

      我们把每一个点扯成两个点。

      一个专门接受入度,一个专门接受出度,然后就是KM裸题了。

      数组模拟链表可能会比邻接矩阵快一些。


    代码

    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    #include <cstdio>
    using namespace std;
    const int INF=1e9+7;
    const int N=205,M=30005;
    struct Gragh{
    	int cnt,y[M],z[M],nxt[M],fst[N];
    	void clear(){
    		cnt=0;
    		memset(fst,0,sizeof fst);
    	}
    	void add(int a,int b,int c){
    		y[++cnt]=b,z[cnt]=c,nxt[cnt]=fst[a],fst[a]=cnt;
    	}
    }g;
    int T,n,m,match[N],ex[N],ey[N],minadd[N];
    bool visx[N],visy[N];
    bool Match(int x){
    	visx[x]=1;
    	for (int i=g.fst[x];i;i=g.nxt[i]){
    		int y=g.y[i];
    		if (visy[y])
    			continue;
    		int add=ex[x]+ey[y]-g.z[i];
    		if (!add){
    			visy[y]=1;
    			if (!match[y]||Match(match[y])){
    				match[y]=x;
    				return 1;
    			}
    		}
    		else
    			minadd[y]=min(minadd[y],add);
    	}
    	return 0;
    }
    int KM(){
    	memset(match,0,sizeof match);
    	memset(ey,0,sizeof ey);
    	for (int i=1;i<=n;i++){
    		ex[i]=-INF;
    		for (int j=g.fst[i];j;j=g.nxt[j])
    			ex[i]=max(ex[i],g.z[j]);
    	}
    	for (int i=1;i<=n;i++){
    		for (int j=1;j<=n;j++)
    			minadd[j]=INF;
    		while (1){
    			memset(visx,0,sizeof visx);
    			memset(visy,0,sizeof visy);
    			if (Match(i))
    				break;
    			int d=INF;
    			for (int j=1;j<=n;j++)
    				if (!visy[j])
    					d=min(d,minadd[j]);
    			for (int j=1;j<=n;j++){
    				if (visx[j])
    					ex[j]-=d;
    				if (visy[j])
    					ey[j]+=d;
    				else
    					minadd[j]-=d;
    			}
    		}
    	}
    	int ans=0;
    	for (int i=1;i<=n;i++){
    		int Max=-INF;
    		for (int j=g.fst[match[i]];j;j=g.nxt[j])
    			if (g.y[j]==i)
    				Max=max(Max,g.z[j]);
    		ans+=Max;
    	}
    	return ans;
    }
    int main(){
    	scanf("%d",&T);
    	while (T--){
    		scanf("%d%d",&n,&m);
    		g.clear();
    		for (int i=1,a,b,c;i<=m;i++){
    			scanf("%d%d%d",&a,&b,&c);
    			g.add(a,b,-c);
    		}
    		printf("%d
    ",-KM());
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    ASP.NET MVC5写.php路由匹配时的问题 ASP.NET MVC 4 在 .NET 4.0 与.NET 4.5 的專案範本差異
    asp.net mvc上传头像加剪裁功能介绍
    图片延迟加载实现
    c#中多线程访问winform控件的若干问题
    C# WinForm实现控件拖动实例介绍
    C# 实现对窗体(Form)换肤
    C#读写txt文件的两种方法介绍
    C#实现JSON序列化与反序列化介绍
    高效的VS调试技巧
    SQL 添加字段和默认值脚本
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/HDU3488.html
Copyright © 2020-2023  润新知