【codevs1227】[网络流24题]方格取数 2

基本和上一题一样,裸费用流
而且更简单

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>

using namespace std;
const int N=10000,inf=0x3f3f3f3f;
int a[N],p[N],inq[N],d[N],val[60][60],head[N];
int n,s,t,m,k,te,sz;
struct edge{
    int u,v,cost,cap,flow,next;
}e[50010];
queue<int>q;
void add(int u,int v,int cap,int cost)
{
    e[++te].u=u;
    e[te].v=v;
    e[te].cap=cap;
    e[te].cost=cost;
    e[te].next=head[u];
    head[u]=te;
}
void insert(int u,int v,int cap,int cost){add(u,v,cap,cost),add(v,u,0,-cost);}
int spfa(int &flow,int &cost)
{
    memset(inq,0,sizeof(inq));
    memset(d,-1,sizeof(d));
    a[s]=inf,d[s]=0,inq[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        for (int i=head[u];i;i=e[i].next)
        {
            int v=e[i].v;
            if (e[i].cap>e[i].flow&&d[u]+e[i].cost>d[v])
            {
                d[v]=d[u]+e[i].cost;
                p[v]=i;
                a[v]=min(a[u],e[i].cap-e[i].flow);
                if (!inq[v])
                {
                    inq[v]=1;
                    q.push(v);
                }
            }
        }
        inq[u]=0;
        q.pop();
    }
    if (d[t]==-1)return false;
    flow+=a[t];
    cost+=a[t]*d[t];
//  cout<<a[t]<<endl<<d[t]<<endl;
    for (int u=t;u!=s;u=e[p[u]].u)
    {
        e[p[u]].flow+=a[t];
        e[p[u]^1].flow-=a[t];
    }
    return true;
}
int mcmf(int &cost)
{
    int flow=0;
    cost=0;
    while(spfa(flow,cost));
    return flow;
}
int kkk(int i,int j){return (i-1)*n+j;}
int main()
{
    te=1;
    cin>>n>>k;
    sz=n*n,s=(sz<<1)+1,t=s+1;
    insert(s,1,k,0);
    insert(sz<<1,t,k,0);
    for(int i=1;i<=n;i++)
    {
        for (int j=1;j<=n;j++)
        {
            scanf("%d",&val[i][j]);
            insert(kkk(i,j),kkk(i,j)+sz,1,val[i][j]);
            insert(kkk(i,j),kkk(i,j)+sz,inf,0);
            if (i<n)insert(kkk(i,j)+sz,kkk(i+1,j),inf,0);
            if (j<n)insert(kkk(i,j)+sz,kkk(i,j+1),inf,0);
        }
    }
    int cost;
//  for (int i=2;i<=te;i+=2)
//  cout<<e[i].u<<' '<<e[i].v<<' '<<e[i].cap<<' '<<e[i].cost<<endl;
    mcmf(cost);
    cout<<cost;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值