您的位置:首页 > 其它

摘取作物

2015-11-18 20:00 197 查看

题目

Feather的农场里有N*M块地,排列成N行,每行M块地。Feather在每块地里种植了不同的农作物。现在这些农作物都成熟了,可以摘取下来出售了。其中第i行第j列的地里的农作物的价值为W[i,j]。

JackRabbit是Feather的好友,平时经常为Feather的农作物除草除虫。为了答谢JackRabbit,Feather决定把一部分农作物送给JackRabbit。JackRabbit很高兴,恨不得一下子把农场里的农作物摘空。

为了防止JackRabbit把农作物摘空,Feather提出了两个条件:

1.每行最多选取两块地;

2.每列最多选取两块地。

这下子把JackRabbit难住了。如何在满足这两个条件的前提下,使得摘取的农作物的价值之和最大呢?

分析

这是一个费用流的模型。

我们发现,这题的限制是每行最多选两个,每列最多选两个,这样的话,我们便可以寻找一种方法在网络流里面体现这样的关系,明显可以这样建图:从源点向每一行连容量为2,费用为0的边,然后每行也向此行的每个点的列连一条容量为1,费用为w[i,j],表示每行可以选两个;接着我们可以从每列向汇点连一条容量为2,费用为0的边。

然后就可以跑最大费用流了。

[code]var
    n,m,t,nu,x,ans,i,j:longint;
    b,las,nex,f,dis,a,re,v:array[0..10000] of longint;
    bz:array[0..10000] of boolean;
procedure insert(x,y,z,k:longint);
begin
    inc(nu);b[nu]:=y;nex[nu]:=las[x];las[x]:=nu;f[nu]:=z;v[nu]:=k;
    inc(nu);b[nu]:=x;nex[nu]:=las[y];las[y]:=nu;f[nu]:=0;v[nu]:=-k;
end;
function spfa:boolean;
var l,r,now,p:longint;
begin
    l:=0;r:=1;fillchar(bz,sizeof(bz),false);fillchar(dis,sizeof(dis),128);dis[0]:=0;a[1]:=0;bz[0]:=true;
    while l<r do begin
        inc(l);now:=a[l];p:=las[now];
        while p<>0 do begin
            if (dis[b[p]]<dis[now]+v[p])and(f[p]>0) then begin
               dis[b[p]]:=dis[now]+v[p];re[b[p]]:=p;
               if not bz[b[p]] then begin bz[b[p]]:=true;inc(r);a[r]:=b[p];end;
            end;p:=nex[p];
        end;
        bz[now]:=false;
    end;
    if dis[t]>0 then ans:=ans+dis[t];
    exit(dis[t]>0);
end;
function min(l,r:longint):longint;
begin
    if l<r then exit(l);exit(r);
end;
procedure find;
var p,x,sum:longint;
begin
    x:=t;sum:=maxlongint;
    while x<>0 do begin
        sum:=min(sum,f[re[x]]);x:=b[re[x] xor 1];
    end;
    x:=t;
    while x<>0 do begin
        dec(f[re[x]],sum);inc(f[re[x] xor 1],sum);x:=b[re[x] xor 1];
    end;
end;
begin
assign(input,'pick.in');reset(input);
assign(output,'pick.out');rewrite(output);
    readln(n,m);
    t:=n*m+1;nu:=1;
    for i:=1 to n do insert(0,i,2,0);
    for i:=1 to m do insert(i+n,t,2,0);
    for i:=1 to n do
        for j:=1 to m do begin
            read(x);
            insert(i,j+n,1,x);
        end;
    while spfa do find;
    writeln(ans);
close(input);close(output);
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: