【codevs1227】方格取数2,费用流

传送门
写在前面:努力提升写网络流的能力
思路:建图和蚯蚓很相似,不过这里(i,j)拆出的两个点x,y之间的边有花费,实际点(i,j)与(i+1,j),(i,j)与(i,j+1)之间的连边要流量inf费用为0,而且拆出的两个点都要向(i+1,j)(i,j+1)的x点连边,因为可能我们之前已经去过(i,j)的权值,并不能再获取,所以要从x走向下一个x(同样y也可以走向下一个x)
注意:无

#include<bits/stdc++.h>
#define inf 0x7f
using namespace std;
int ans,n,k,s,t,tot=1,cnt,first[20000],dis[20000],up[20000];
bool vis[20000];
queue<int>q;
struct edge
{
    int u,v,w,cost,next;
}e[40000];
struct os
{
    int x,y,data;
}a[102][52];
void add(int x,int y,int z,int c)
{
    e[++tot].u=x;
    e[tot].v=y;
    e[tot].w=z;
    e[tot].cost=c;
    e[tot].next=first[x];
    first[x]=tot;
}
bool spfa()
{
    memset(dis,63,sizeof(dis));
    memset(up,0,sizeof(up));
    dis[s]=0;vis[s]=1;
    q.push(s);
    while (!q.empty())
    {
        int k=q.front();
        q.pop();
        vis[k]=0;
        for (int i=first[k];i;i=e[i].next)
        if (e[i].w&&dis[e[i].v]>dis[k]+e[i].cost)
        {
            dis[e[i].v]=dis[k]+e[i].cost;
            up[e[i].v]=i;
            if (!vis[e[i].v]) vis[e[i].v]=1,q.push(e[i].v);
        }
    }
    return dis[t]<0x7ffff;
}
void flow()
{
    int minn=0x7fffffff;
    for (int i=up[t];i;i=up[e[i].u])
        minn=min(minn,e[i].w);
    for (int i=up[t];i;i=up[e[i].u])
        e[i].w-=minn,
        e[i^1].w+=minn,
        ans+=minn*e[i].cost;
}
main()
{
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
            scanf("%d",&a[i][j].data),
            a[i][j].data=-a[i][j].data,
            a[i][j].x=++cnt,a[i][j].y=++cnt,
            add(cnt-1,cnt,1,a[i][j].data),
            add(cnt,cnt-1,0,-a[i][j].data);
    s=++cnt;t=++cnt;
    add(s,1,inf,0);
    add(1,s,0,0);
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
        {
            if (i+1<=n)
                add(a[i][j].x,a[i+1][j].x,inf,0),
                add(a[i+1][j].x,a[i][j].x,0,0),
                add(a[i][j].y,a[i+1][j].x,inf,0),
                add(a[i+1][j].x,a[i][j].y,0,0);
            if (j+1<=n)
                add(a[i][j].x,a[i][j+1].x,inf,0),
                add(a[i][j+1].x,a[i][j].x,0,0),
                add(a[i][j].y,a[i][j+1].x,inf,0),
                add(a[i][j+1].x,a[i][j].y,0,0);
        }
    add(cnt-2,t,inf,0);
    add(t,cnt-2,0,0);
    add(cnt-3,t,inf,0);
    add(t,cnt-3,0,0);
    while (k--&&spfa()) flow();
    printf("%d",-ans);
}

你可能感兴趣的:(【codevs1227】方格取数2,费用流)