HLG 1407 Leyni的游戏【KM】
题意:
有一个n * m的矩阵,每个元素都是非负的,每一行,每一列的边缘都有一个按钮(即n + m个),对应着第1行,第2行,第3行,…,第n行,第1列,第2列,第3列,…,第m列。每当他按下某个按钮,那么对应的一行或者一列的所有元素将减去1,值为0的元素不受到影响。
他想知道,他最少需要按多少次按钮,能够将整个矩阵都变成0。
分析: 有点类似最小点权覆盖,以行为 X 集合, 以列为 Y 集合,以 g[i][j] 为边权建立二分图,完美匹配下的最大权值即为答案,
最大权匹配算法要保证左右集合相等,因此在点不够的情况下要补点!!!
View Code
#include<stdio.h> #include<string.h> #define INF 0x1f1f1f int sx[202],sy[202]; int lx[202],ly[202]; int link[202]; int cx[202]; int g[202][202]; int n; int find(int x) { int i; sx[x]=1; for(i=1;i<=n;i++) if(!sy[i]&&lx[x]+ly[i]==g[x][i]) { sy[i]=1; if(link[i]==0||find(link[i])) { link[i]=x; return 1; } } return 0; } int KM() { int i,j,v,dmin,sum; for(i=1;i<=n;i++) { lx[i]=-INF; for(j=1;j<=n;j++) if(g[i][j]>lx[i]) lx[i]=g[i][j]; } memset(sy,0,sizeof(sy)); memset(link,0,sizeof(link)); for(v=1;v<=n;v++) { memset(sx,0,sizeof(sx)); memset(sy,0,sizeof(sy)); while(1) { if(find(v)) break; dmin=INF; for(i=1;i<=n;i++) if(sx[i]) for(j=1;j<=n;j++) if(!sy[j]&&lx[i]+ly[j]-g[i][j]<dmin) dmin=lx[i]+ly[j]-g[i][j]; for(i=1;i<=n;i++) { if(sx[i]){ lx[i]-=dmin; sx[i]=0;} if(sy[i]){ ly[i]+=dmin; sy[i]=0;} } } } sum=0; for(i=1;i<=n;i++) sum+=g[link[i]][i]; return sum; } int main() { int i,j,m; while(scanf("%d%d",&n,&m)!=EOF) { memset(g,0,sizeof(g)); for(i=1;i<=n;i++) for(j=1;j<=m;j++) scanf("%d",&g[j][i]); if(n<m) n=m; printf("%d\n",KM()); } return 0; }



浙公网安备 33010602011771号