首页 > 代码库 > [CodeVs1227]方格取数2(最大费用最大流)

[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>
const int maxn=5100,inf=1000000000;
struct poii{int too,pre,c,f,cf,v;}e[1000010];
int h[maxn],dist[maxn],pre[maxn],last[maxn];
int sum,ans,n,m,tot,x,k,z;
bool v[maxn];
using namespace std;
void add(int x,int y,int c,int v)
{
    e[++tot].too=y;e[tot].pre=last[x];last[x]=tot;
    e[tot].c=e[tot].cf=c;e[tot].v=v;
    e[++tot].too=x;e[tot].pre=last[y];last[y]=tot;e[tot].v=-v;
}
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 spfa(int s)
{
    int front=0,rear=1;
    for(int i=0;i<=sum;i++)dist[i]=-inf,v[i]=0,pre[i]=-1;
    dist[s]=0;v[s]=1;h[1]=s;
    while(front!=rear)
    {
        if(front>maxn)front=-1;
        int now=h[++front];
        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,rear>maxn&&(rear=-1),h[++rear]=too;
        }
        v[now]=0;
    }
}
void ford(int s,int t)
{
    spfa(s);
    while(pre[t]!=-1)
    {
        int mincf=inf,cnt=0;;
        for(int i=pre[t];i!=-1;i=pre[e[i^1].too])
        mincf=min(mincf,e[i].cf);
        ans+=mincf*dist[t];
        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);int x=num(i,j);
        add(x,x+n*n,1,z);
        add(x,x+n*n,inf,0);
        if(i+1<=n)add(x+n*n,num(i+1,j),inf,0);
        if(j+1<=n)add(x+n*n,num(i,j+1),inf,0);
    }
    ford(0,sum);
    printf("%d\n",ans);
}
View Code

 

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