[CodeVs1227]方格取数2(最大费用最大流)

  网络流24题的坑还没填完,真的要TJ?

  题目大意:一个n*n的矩阵,每格有点权,从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,这样一共走K次,现在要求K次所达到的方格的数的和最大。

  啊简单的费用流。每个点i拆成i和i',连一条容量为1的边价值为点权,再连一条容量inf的边价值为0来让这个点能被经过,然后S连(1,1)容量k价值0,i'和右、下的点连容量inf价值0的边,(n,n)'连T容量inf价值0,跑最大费用最大流。

  MDZZ看见n50我就开50,这是矩阵啊喂

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int inf=1000000000,maxn=5100;
struct poi{int dis,pos;};
struct zs{int too,pre,c,cf,v,f;}e[1000010];
priority_queue<poi>q;
bool operator <(poi a,poi b){return a.dis<b.dis;};
int n,k,z,tot,sum,ans;
int last[maxn],dist[maxn],pre[maxn];
bool v[maxn];
void read(int &k)
{
    k=0;int f=1;char c=getchar();
    while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
    while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();
    k*=f;
}
void add(int x,int y,int c,int v)
{
    e[++tot].too=y;e[tot].c=e[tot].cf=c;e[tot].v=v;
    e[tot].pre=last[x];last[x]=tot;
    e[++tot].too=x;e[tot].v=-v;
    e[tot].pre=last[y];last[y]=tot;
}
void spfa(int x)
{
    for(int i=0;i<=sum;i++)pre[i]=-1,dist[i]=-inf,v[i]=0;
    dist[x]=0;v[x]=1;q.push((poi){0,x});
    while(!q.empty())
    {
        int now=q.top().pos;q.pop();
        for(int i=last[now],too=e[i].too;i;i=e[i].pre,too=e[i].too)
        if(e[i].cf)
        if(dist[too]<dist[now]+e[i].v)
        {
            dist[too]=dist[now]+e[i].v;pre[too]=i;
            if(!v[too])v[too]=1,q.push((poi){dist[too],too});
        }
        v[now]=0;
    }
}
void ford(int s,int t)
{
    spfa(s);
    while(pre[t]!=-1)
    {
        int mincf=inf;
        for(int i=pre[t];i!=-1;i=pre[e[i^1].too])
        mincf=min(mincf,e[i].cf);
        ans+=dist[t]*mincf;
        for(int i=pre[t];i!=-1;i=pre[e[i^1].too])
        {
            e[i].f+=mincf;e[i^1].f=-e[i].f;
            e[i].cf-=mincf;e[i^1].cf+=mincf;
        }
        spfa(s);
    }
}
int num(int x,int y){return (x-1)*n+y;}
int main()
{
    tot=1;
    read(n);read(k);sum=2*n*n+1;
    add(0,1,k,0);add(2*n*n,sum,k,0);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    {
        read(z);
        add(num(i,j),num(i,j)+n*n,1,z);
        add(num(i,j),num(i,j)+n*n,inf,0);
        if(i!=n)add(num(i,j)+n*n,num(i+1,j),inf,0);
        if(j!=n)add(num(i,j)+n*n,num(i,j+1),inf,0);
    }
    ford(0,sum);
    printf("%d
",ans);
}
View Code
原文地址:https://www.cnblogs.com/Sakits/p/6891963.html