[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);
}

时间: 2024-10-17 04:23:24

[CodeVs1227]方格取数2(最大费用最大流)的相关文章

HDU 3376 &amp;&amp; 2686 方格取数 最大和 费用流裸题

题意: 1.一个人从[1,1] ->[n,n] ->[1,1] 2.只能走最短路 3.走过的点不能再走 问最大和. 对每个点拆点限流为1即可满足3. 费用流流量为2满足1 最大费用流,先给图取负,结果再取负,满足2 #include <stdio.h> #include <string.h> #include <iostream> #include <math.h> #include <queue> #include <set&

【Codevs1227】方格取数2(费用流)

题意:给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000) 现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0, 这样一共走K次,现在要求K次所达到的方格的数的和最大. n<=50,k<=10 思路:费用流 将每个点裂成一个出点和一个入点(i,j,1..2),这个思路与最大流类似 (i,j,1)->(i,j,2) 连两条边: 容量为1,费用为a[i,j] 容量为K,费用为0 (i,j,2)->

HDU 3376 &amp;amp;&amp;amp; 2686 方格取数 最大和 费用流裸题

题意: 1.一个人从[1,1] ->[n,n] ->[1,1] 2.仅仅能走最短路 3.走过的点不能再走 问最大和. 对每一个点拆点限流为1就可以满足3. 费用流流量为2满足1 最大费用流,先给图取负,结果再取负,满足2 #include <stdio.h> #include <string.h> #include <iostream> #include <math.h> #include <queue> #include <s

NEU 1458 方格取数(网络流之费用流)

题目地址:NEU 1458 跟杭电上的那两个方格取数不太一样..这个可以重复,但是取和的时候只能加一次.建图思路基本一会就出来.同样的拆点,只不过这题需要再拆个边,其中一条费用0,另一条费用为那个点处的值.流量都限制为1.然后剩下的都跟杭电上的那两个差不多了.因为把数组开小了WA了好几发..(我前面居然还专门检查了一下数组大小,居然当时还认为没开小...对自己无语..) 代码如下: #include <iostream> #include <stdio.h> #include &l

Luogu1006 传纸条 与 Luogu P2045方格取数加强版 (费用流)

Luogu1006 传纸条 与 Luogu P2045方格取数加强版 其实就是这几道题 在一个有m*n 个方格的棋盘中 每个方格中有一个正整数 现要从在方格中从左上角到右下角取数,只能向右或向下走 每走到一个格子就可以把这个位置上的数取走(下次经过就没有了) 1.让你走1次,求取出的数的总和最大是多少 2.让你走2次,求取出的数的总和最大是多少 3.让你走k次,求取出的数的总和最大是多少 对于第一问,十分显然. 设\(f[i][j]\)表示\(i\)行\(j\)列的最大价值,转移即可. 第二问,

hdu 3657 最小割的活用 / 奇偶方格取数类经典题 /最小割

题意:方格取数,如果取了相邻的数,那么要付出一定代价.(代价为2*(X&Y))(开始用费用流,敲升级版3820,跪...) 建图:  对于相邻问题,经典方法:奇偶建立二分图.对于相邻两点连边2*(X&Y),源->X连边,Y->汇连边,权值w为点权. ans=总点权-最小割:如果割边是源->X,表示x不要选(是割边,必然价值在路径上最小),若割边是Y-汇点,同理:若割边是X->Y,则表示选Y点且选X点, 割为w( 2*(X&Y) ). 自己的确还没有理解其本质

HRBUST 1214 方格取数

方格取数 Time Limit: 1000ms Memory Limit: 65535KB This problem will be judged on HRBUST. Original ID: 121464-bit integer IO format: %lld      Java class name: Main 设有N*N的方格图(N<=10),我们将其中的某些方格中填入正整数,而其他的方格中则放人数字0.如下图所示(见样例 ,黄色和蓝色分别为两次走的路线,其中绿色的格子为黄色和蓝色共同走

NOIP200003方格取数

NOIP200003方格取数 难度级别: D: 编程语言:不限:运行时间限制:1000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 XYZ 是首师大附中信息技术团编程大神之一,尤其近两个月水平提升迅猛,一发不可收拾.老师说他前途不可估量,于是他有一点小骄傲,好像没有什么题能难住他.这让另一位编程高手 WJH 看不下去了,于是要求出一道题考考他,如果 10 分钟内做不出来,以后不许再这么“嚣张”,XYZ 欣然同意.WJH 要求 XYZ 帮助 ZYT 解决一个问题

vijos 1563 疯狂的方格取数

P1653疯狂的方格取数 Accepted 标签:天才的talent[显示标签] 背景 Due to the talent of talent123,当talent123做完NOIP考了两次的二取方格数和vijos中的三取方格数后,突发奇想.... 描述 在一个宽M,长N的矩阵中,请你编一个程序,n次从矩阵的左上角走到矩阵的右下角,每到一处,就取走该处的数字,请你选择一种走法使取得的数字的和最大,并输出其最大值.其中:3<=M<=20 M<=N<=100 1<=n<=1