[UVA11383] Golden Tiger Claw

题目

原题链接

解说

\(gyz\)挑的分享题,洛谷上的翻译也是他传的\((orz)\)
最开始\(gyz\)要是不说是图论我可能还真想不到这个方向,但是他直接开始就剧透说这是个二分图了……
那就简单了,直接利用二分图\(km\)算法中\(x[i]+y[i]>=w(x,y)\)解决。

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=500+3,inf=0x3f3f3f3f;
int n,nx,ny,link[maxn],lx[maxn],ly[maxn],slack[maxn],a[maxn][maxn],sum;
bool visx[maxn],visy[maxn];
inline int read(){
   int s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
} 
bool dfs(int x){
	visx[x]=1;
	for(int y=1;y<=ny;y++){
		if(visy[y]) continue;
		int t=lx[x]+ly[y]-a[x][y];
		if(!t){
			visy[y]=1;
			if(link[y]==-1||dfs(link[y])){
				link[y]=x;
				return 1;
			}
		}
		else if(slack[y]>t) slack[y]=t;
	}
	return 0;
}
int km(){
	memset(link,-1,sizeof(link));
	memset(ly,0,sizeof(ly));
	for(int i=1;i<=nx;i++){
		lx[i]=-1*inf;
		for(int j=1;j<=ny;j++){
			if(a[i][j]>lx[i]) lx[i]=a[i][j];
		}
	}
	for(int x=1;x<=nx;x++){
		for(int i=1;i<=ny;i++) slack[i]=inf;
		while(1){
			memset(visx,0,sizeof(visx));
			memset(visy,0,sizeof(visy));
			if(dfs(x)) break;
			int dis=inf;
			for(int i=1;i<=ny;i++) if(!visy[i]&&dis>slack[i]) dis=slack[i];
			for(int i=1;i<=nx;i++) if(visx[i]) lx[i]-=dis;
			for(int i=1;i<=ny;i++){
				if(visy[i]) ly[i]+=dis;
				else slack[i]-=dis;
			}
		}
	}
	int res=0;
	for(int i=1;i<=ny;i++) if(link[i]>-1) res+=a[link[i]][i];
	return res;
}
int main(){
	while(scanf("%d",&n)!=EOF){
		sum=0;
		for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                a[i][j]=read();
            }
        }
        nx=n;ny=n;
        int ans=km();
        for(int i=1;i<=n;i++){
            printf("%d ",lx[i]);
            sum+=lx[i];
        }
        printf("\n");
        for(int i=1;i<=n;i++){
            printf("%d ",ly[i]);
            sum+=ly[i];
        }
        printf("\n");
        printf("%d\n",sum);
	}
	return 0;
}

幸甚至哉,歌以咏志。

posted @ 2020-05-10 17:56  DarthVictor  阅读(131)  评论(0编辑  收藏  举报
莫挨老子!