[jzoj3447]【NOIP2013模拟联考2】摘取作物(pick)

版权声明:本文为博主原创文章,转载时请标明出处。 https://blog.csdn.net/FarmerJohnOfZS/article/details/80508266

Solution

典型的二维关系.

对于每一个点,连向它所对应的行和列,源点向每行连一条,每列向汇点连一条.

实际上,本题只需要 ( n + 1 ) + ( m + 1 ) + 2 个点即可

对于每一个点 它实际是一个物品 将对应的行列容量减一

以此连接每行每列即可

Code

#include <cstdio>
#include <cstring>
#include <iostream>
#define oo 2139062143
#define fo(i,x,y) for (int i=(x);i<=(y);++i)
using namespace std;
const int N=33*2,M=N*2*2;
int n,m,p;
int S,T;
int w[N][N];
int cs[N][N],f[N][N];
int d[N*10],dis[N];
int vis[N],pre[N],ans;
int spfa()
{
    //每次只走一条路径
    memset(dis,138,sizeof dis);
    memset(vis,0,sizeof vis);
    int hd=0,tl=1;
    d[1]=S;dis[S]=0;
    vis[S]=1;
    while(hd++<tl)
    {
        int x=d[hd];
        fo(i,1,n+m+2)
        if(x!=i&&f[x][i]>0&&dis[x]+cs[x][i]>dis[i])
        {
            pre[i]=x;
            dis[i]=dis[x]+cs[x][i];
            if(!vis[i]) vis[i]=1,d[++tl]=i;
        }
        vis[x]=0;
    }
    if(dis[T]<0)return 0;
    int x=T,tp=oo;
    while(x!=S)
    {
        tp=min(tp,f[pre[x]][x]);
        x=pre[x];
    }
    x=T;
    while(x!=S)
    {
        f[pre[x]][x]-=tp,f[x][pre[x]]+=tp;
        x=pre[x];
    }
    ans+=dis[T];
    return 1;
}
int main()
{
    freopen("pick.in","r",stdin);
    freopen("pick.out","w",stdout);
    scanf("%d%d",&n,&m);
    S=n+m+1,T=n+m+2;
    fo(i,1,n) fo(j,1,m) 
    {
        scanf("%d",&w[i][j]);
        f[i][j+n]=1;
        cs[i][j+n]=w[i][j];
        cs[j+n][i]=-w[i][j];
    }
    fo(i,1,n) f[S][i]=2;
    fo(i,1+n,n+m) f[i][T]=2;
    while(spfa());
    printf("%d\n",ans);
    return 0;
}











猜你喜欢

转载自blog.csdn.net/FarmerJohnOfZS/article/details/80508266
今日推荐