因为要用^
来取反向边 所以每次加边加两条!来保证'^'的值是对的
题目规定取一次后变为0! 所以流量为0 这时 我们再加一条花费为0 的边来保证联通!!
#include <iostream>
#include <cstdio>
#include <cstring>
#define INF 100000000
using namespace std;
int id[51][51][2],cnt;
int n,k;
int g[500000+10],num[500000+10],nnext[500000+10],cost[500000+10],flow[500000+10],tot=2;
int s,t;
int fa[50000+10],fx[50000+10];
int team[50000*4],head,tail;
bool b[50000+10];
int d[50000+10];
void Add(int x,int y,int z,int f)
{
num[tot]=y;
nnext[tot]=g[x];
g[x]=tot;
cost[tot]=z;
flow[tot]=f;
tot++;
}
bool spfa()
{
head=tail=0;
memset(b,false,sizeof(b));
for(int i=1;i<=cnt;i++) d[i]=-INF;
d[s]=0;b[s]=true;team[++tail]=s;
while(head<tail)
{
int x=team[++head];b[x]=false;
for(int i=g[x];i;i=nnext[i])
{
int tmp=num[i];
if(flow[i]!=0&&d[tmp]<d[x]+cost[i])
{
fa[tmp]=x;
fx[tmp]=i;
d[tmp]=d[x]+cost[i];
if(!b[tmp]) team[++tail]=tmp,b[tmp]=true;
}
}
}
if(d[t]==-INF) return false;
return true;
}
int main()
{
scanf("%d %d",&n,&k);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
int tmp;
scanf("%d",&tmp);
id[i][j][0]=++cnt;
id[i][j][1]=++cnt;
if(i-1>=1)
Add(id[i-1][j][1],id[i][j][0],0,INF),Add(id[i][j][0],id[i-1][j][1],0,0);
if(j-1>=1)
Add(id[i][j-1][1],id[i][j][0],0,INF),Add(id[i][j][0],id[i][j-1][1],0,0);
Add(id[i][j][0],id[i][j][1],tmp,1),Add(id[i][j][1],id[i][j][0],-tmp,0);
Add(id[i][j][0],id[i][j][1],0,INF),Add(id[i][j][1],id[i][j][0],0,0);
}
s=++cnt;t=++cnt;
Add(s,id[1][1][0],0,k),Add(id[1][1][0],s,0,0);
Add(id[n][n][1],t,0,k),Add(t,id[n][n][1],0,0);
int ans=0;
while(spfa())
{
int tmp=t;
while(tmp!=s)
{
ans+=cost[fx[tmp]];
flow[fx[tmp]]--;
flow[fx[tmp]^1]++;
tmp=fa[tmp];
}
}
printf("%d\n",ans);
return 0;
}