zoukankan      html  css  js  c++  java
  • UVA11383 Golden Tiger Claw

    题意:

    给定一个N*N的矩阵,每个位置有一个正整数w(i,j)
    要求对每行赋一个值row(i),每列赋一个值col(i)
    使得在满足对于任意w(i,j),有w(i,j)<=row(i)+col(j)的前提下,最小化所有row(i)和col(i)之和
    N<=500
    链接

    思路:

    例题。
    考虑KM算法里的不等式l(x)+l(y)>=w(i,j)
    跑完KM算法后所有l(x)+l(y)即为最小
    直接套KM算法即可(这里和带权最大完美没有关系~~)

    注意:

    第一次写KM算法。
    要注意变量d和vis2[i]的赋值

    code:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=505;
    int n;
    int lk[N][N],lb1[N],lb2[N],match[N],slack[N];
    bool vis1[N],vis2[N];
    inline int read()
    {
    	int s=0,w=1; char ch=getchar();
    	for(;!isdigit(ch);ch=getchar())if(ch=='-')w=-1;
    	for(;isdigit(ch);ch=getchar())s=(s<<1)+(s<<3)+(ch^48);
    	return s*w;
    }
    bool dfs(int x)
    {
    	vis1[x]=1;
    	for(int i=1;i<=n;++i)
    	{
    		if(vis2[i]) continue;
    		int gap=lb1[x]+lb2[i]-lk[x][i];
    		if(!gap)
    		{
    			vis2[i]=1;
    			if(match[i]==-1||dfs(match[i]))
    			{
    				match[i]=x;
    				return true;
    			} 
    		}
    		else slack[i]=min(slack[i],gap);
    	}
    	return false;
    }
    inline void km()
    {
    	for(int i=1;i<=n;++i)match[i]=-1;
    	for(int i=1;i<=n;++i)lb2[i]=0;
    	for(int i=1;i<=n;++i)
    	{
    		lb1[i]=lk[i][1];
    		for(int j=2;j<=n;++j)
    			lb1[i]=max(lb1[i],lk[i][j]);
    	}
    	for(int i=1;i<=n;++i)
    	{
    		for(int j=1;j<=n;++j)slack[j]=1e9;
    		while(1)
    		{
    			for(int j=1;j<=n;++j)vis1[j]=vis2[j]=0;
    			if(dfs(i)) break;
    			int d=1e9;
    			for(int j=1;j<=n;++j)
    				if(!vis2[j])d=min(d,slack[j]);
    			for(int j=1;j<=n;++j)
    			{
    				if(vis1[j]) lb1[j]-=d;
    				if(vis2[j]) lb2[j]+=d;
    				else slack[j]-=d;
    			}
    		}
    	}
    	int ans=0;
    	for(int i=1;i<=n;++i)printf("%d ",lb1[i]);
    	puts("");
    	for(int i=1;i<=n;++i)printf("%d ",lb2[i]);
    	for(int i=1;i<=n;++i)ans+=lb1[i]+lb2[i];
    	puts("");
    	printf("%d
    ",ans);
    }
    int main()
    {
    	while(~scanf("%d",&n))
    	{
    		for(int i=1;i<=n;++i)
    			for(int j=1;j<=n;++j)
    				lk[i][j]=read();
    		km();
    	}
    	return 0;
    }
    

    这里推荐一个KM算法讲得比较形象的:这里

  • 相关阅读:
    关于C++中类的static和const成员
    你搞图论有毛用啊!!
    getopt()
    算法设计与分析求最大子段和问题(蛮力法、分治法、动态规划法) C++实现
    CF183 div2 解题报告
    程序员面试中什么最重要?
    php函数基础(一)
    可变参数列表
    ThinkPHP5+小程序商城 网盘视频
    svn里update以后还是有红色的感叹号怎么办
  • 原文地址:https://www.cnblogs.com/zmyzmy/p/12494676.html
Copyright © 2011-2022 走看看