Description
Feather的农场里有N*M块地,排列成N行,每行M块地。Feather在每块地里种植了不同的农作物。现在这些农作物都成熟了,可以摘取下来出售了。其中第i行第j列的地里的农作物的价值为W[i,j]。
JackRabbit是Feather的好友,平时经常为Feather的农作物除草除虫。为了答谢JackRabbit,Feather决定把一部分农作物送给JackRabbit。JackRabbit很高兴,恨不得一下子把农场里的农作物摘空。
为了防止JackRabbit把农作物摘空,Feather提出了两个条件:
1.每行最多选取两块地;
2.每列最多选取两块地。
这下子把JackRabbit难住了。如何在满足这两个条件的前提下,使得摘取的农作物的价值之和最大呢?
Solution
很明显的,每行建一个点,每列建一个点,连边随便YY一下,跑个最大费用可行流就好
Code
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
#define N 35
using namespace std;
int n,m,a[2*N][2*N],f[2*N][2*N],w[2*N][2*N],v[N][N],n1,s,dt[10*N],dis[2*N][3];
bool bz[2*N];
int link(int x,int y,int r,int p)
{
a[x][++a[x][0]]=y;
a[y][++a[y][0]]=x;
f[x][y]=r;
w[x][y]=p;
w[y][x]=-p;
}
bool spfa()
{
memset(bz,0,sizeof(bz));
memset(dis,128,sizeof(dis));
dt[1]=1;
bz[1]=1;
dis[1][0]=0;
int p,k,l=0,r=1,i;
while(l<r)
{
k=dt[++l];
fo(i,1,a[k][0])
{
p=a[k][i];
if (dis[p][0]<dis[k][0]+w[k][p]&&f[k][p]>0)
{
dis[p][0]=dis[k][0]+w[k][p];
dis[p][1]=k;
if (bz[p]==0)
{
dt[++r]=p;
bz[p]=1;
}
}
}
bz[k]=0;
}
return(dis[n1][0]>0);
}
void get()
{
int i=n1,j=dis[i][1];
s+=dis[n1][0];
while (j>0)
{
f[j][i]-=1;
f[i][j]+=1;
i=j;
j=dis[j][1];
}
}
int main()
{
cin>>n>>m;
int i,j;
fo(i,1,n)
fo(j,1,m)
scanf("%d",&v[i][j]);
n1=n+m+2;
fo(i,1,n) link(1,1+i,2,0);
fo(i,1,m) link(1+n+i,n1,2,0);
fo(i,1,n)
fo(j,1,m) link(1+i,1+n+j,1,v[i][j]);
while (spfa()) get();
cout<<s;
}