传送门
写在前面:努力提升写网络流的能力
思路:建图和蚯蚓很相似,不过这里(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);
}