codevs1227

费用流,其实是求传输一个容量为k的流的最大费用。主要是建图。原点为0,和1连上一条容量为k,费用为0的边,中间每个点拆成两个1和2,连上一条边,容量为k,费用为c,再连一条容量为比k大,费用为0的边,这样是为了跑完费用之后能继续跑拆完后的点和。然后和其他边连上就可以了。n*n和汇点连上一条容量为k,费用为0的边。我就是每次跑了一个容量为1的流,求打脸,不知道对不对。

#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
const int inf=0x3f3f3f3f;
struct edge
{
    int to,nxt,c,f;
}e[30011];
int n,k,cur,ans,cnt=1;
int dist[30011],used[30011],pree[30011],prev[30011],g[30011];
void link(int u,int v,int f,int c)
{
    e[++cnt].nxt=g[u];
    g[u]=cnt;
    e[cnt].f=f;
    e[cnt].to=v;
    e[cnt].c=c;
}
void ins(int u,int v,int f,int c)
{
    link(u,v,f,c);
    link(v,u,0,-c);
}
int Min(int x,int y)
{
    return x<y?x:y;
}
bool spfa()
{
    queue<int>q;
    memset(dist,-1,sizeof(dist));
    memset(used,0,sizeof(used));
    dist[0]=0;
    q.push(0);
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        used[u]=0;
        for(int i=g[u];i;i=e[i].nxt)
        {
            int v=e[i].to,w=e[i].c;
            if(e[i].f&&dist[v]<dist[u]+w)
            {
                dist[v]=dist[u]+w;
                prev[v]=u; pree[v]=i;
                if(!used[v])
                {
                    q.push(v);
                    used[v]=1;
                }
            }
        }
    }
    return dist[10010]!=-1;
}
int MinCostFlow()
{
    int u=10010,sum=inf;
    while(u)
    {
        e[pree[u]].f--;
        e[pree[u]^1].f++;
        u=prev[u];
    }
//    cout<<dist[10010]<<endl;
    return dist[10010];
}
void MinFlow()
{
    while(spfa())
    {
        cur+=MinCostFlow();
        if(cur>ans) ans=cur;
    }
    printf("%d",ans);
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            int x; scanf("%d",&x);
            ins((i-1)*n+j,(i-1)*n+j+n*n,1,x);
            ins((i-1)*n+j,(i-1)*n+j+n*n,k,0);
            if(i!=n)
            {
                ins((i-1)*n+j+n*n,i*n+j,k,0);
            }
            if(j!=n)
            {
                ins((i-1)*n+j+n*n,(i-1)*n+j+1,k,0);
            }
        }
    }
    ins(0,1,k,0);
    ins(n*n*2,10010,k,0);
    MinFlow();
    return 0;
}
时间: 2024-12-19 17:57:31

codevs1227的相关文章

【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)->

[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容

codevs1033 蚯蚓的游戏问题

Description 在一块梯形田地上,一群蚯蚓在做收集食物游戏.蚯蚓们把梯形田地上的食物堆积整理如下: a(1,1)  a(1,2)…a(1,m) a(2,1)  a(2,2)  a(2,3)…a(2,m)  a(2,m+1) a(3,1)  a (3,2)  a(3,3)…a(3,m+1)  a(3,m+2) …… a(n,1)   a(n,2)   a(n,3)…           a(n,m+n-1) 它们把食物分成n行,第1行有m堆的食物,每堆的食物量分别是a(1,1),a(1,2

【codevs1277】 方格取数 2

http://codevs.cn/problem/1227/ (题目链接) 题意 N*N的方格,每个格子中有一个数,寻找从(1,1)走到(N,N)的K条路径,使得取到的数的和最大. Solution 经典的费用流应用吧. 额外添加源点S和汇点T,分别与(1,1)和(N,N)连边.把棋盘中每个点拆成两个,连两条弧.其中一条容量为1,费用为该点的数字大小:另一条容量为inf,费用为0.这就表示一个点的数只能取一次,然后跑最大费用最大流即可. 细节 数组开小.. 代码 // codevs1227 #i