我的第一道费用流,难得一次性ac啊,哈哈!不过 debug 了很久。。。建图要小心,要特别小心!!!!!这道题和大一暑假集训做的那个采蘑菇的 gondar 很像,记得哥当时用了一个犀利的一逼的dp搞定了。。。其实一点都不犀利。。。然后 racebug 问我如果有 10 个人怎么办,我想尼玛 10 个人就开个 11 维数组呗。。- -!然后 racebug 说那就果断超时了嘛。。。又说。。那果断就是最大流了!(其实是费用流啊!我说我学完最大流咋还想不出建图。。)。。哥当时傻了。。网络流是啥东西,比 dp 还要牛逼?……*&%%&……%……&% 现在哥终于做出来了。!!。。。
最小费最大流有两种算法,
一种是消圈法,这种方法很好证明,只要证明无负环圈的充要条件是最大流取得最小费~
还有一种是每次用 spfa 搜索最小费用路,然后在这条路上增广,其实就是保证每次增广之后在当前的流量下都是最小费用,所以增广到不能增广的时候就能获得最小费下的最大流了,增广用的是EdmondsKarp算法,因为 spfa的复杂度比 bfs 要高一点,所以总复杂度要比最大流的EdmondsKarp 高一点,也不会高很多,大概就是O(L*V*e2),L是 spfa 里复杂度的常数,一般小于2。
不过这种算法哥还没证明,只会用。。艹。。。。
还有一种很犀利的费用流的算法就是 zkw 算法, sap 多路增广加 km 算法(不过sap不能加当前弧优化,否则就等着wa!),也可以 dinic 加 km,其中 km 算法就是最佳匹配的那个km(最小费最大流也能搞最佳匹配,神器!),zkw哥还不会。。。改天再研究研究。。nnd~
#include<iostream>
#include<vector>
#include<cstring>
#include<queue>
#include<cstdio>
#include<string>
#include<iomanip>
#include<cassert>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 5011;
const int maxc = 55;
const int end = 5001;
const int add = 2500;
const int dir[2][2]={{0,1},{1,0}};
struct zz
{
int from;
int to;
int c;
int cost;
int id;
}zx,tz;
vector<zz>g[maxn];
queue<int>q;
int n,k;
int a[maxc][maxc];
int way[maxn];
bool inq[maxn];
int backid[maxn];
bool yes(int x,int y)
{
if(1<=x && x<=n && y>=1 && y<=n)
{
return true;
}
return false;
}
int num(int x,int y)
{
return (x-1)*n + y;
}
int dx(int temp)
{
return (temp-1)/n + 1;
}
int dy(int temp)
{
return (temp-1)%n + 1;
}
void build()
{
for(int i=0;i<maxn;i++)
{
g[i].clear();
}
zx.from = 0;
zx.to = 1;
zx.cost = 0;
zx.c = inf;
zx.id = g[1].size();
g[0].push_back(zx);
swap(zx.from,zx.to);
zx.c = 0;
zx.id = g[0].size() - 1;
g[1].push_back(zx);
int now,to,nowx,nowy,n2;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
now = num(i,j);
n2 = now + add;
for(int k=0;k<2;k++)
{
nowx = i + dir[k][0];
nowy = j + dir[k][1];
if(!yes(nowx,nowy))
{
continue;
}
to = num (nowx,nowy);
zx.from = now;
zx.to = to;
zx.cost = 0;
zx.c = inf;
zx.id = g[to].size();
g[now].push_back(zx);
swap(zx.from,zx.to);
zx.c = 0;
zx.id = g[now].size() - 1;
g[to].push_back(zx);
zx.from = n2;
zx.to = to;
zx.cost = 0;
zx.c = inf;
zx.id = g[zx.to].size();
g[zx.from].push_back(zx);
swap(zx.from,zx.to);
zx.c = 0;
zx.id = g[zx.to].size() - 1;
g[zx.from].push_back(zx);
}
zx.from = now;
zx.to = n2;
zx.c = 1;
zx.cost = a[i][j];
zx.id = g[n2].size();
g[now].push_back(zx);
swap(zx.from,zx.to);
zx.c = 0;
zx.cost = -a[i][j];
zx.id = g[now].size() - 1;
g[n2].push_back(zx);
}
}
zx.from = n*n ;
zx.to = end;
zx.c = inf;
zx.cost = 0;
zx.id = g[end].size();
g[zx.from].push_back(zx);
swap(zx.from,zx.to);
zx.id = g[n*n].size() - 1;
zx.c = 0;
g[end].push_back(zx);
zx.from = n*n + add;
zx.to = end;
zx.c = inf;
zx.cost = 0;
zx.id = g[end].size();
g[zx.from].push_back(zx);
swap(zx.from,zx.to);
zx.c = 0;
zx.id = g[zx.to].size() - 1;
g[zx.from].push_back(zx);
return ;
}
void spfa()
{
memset(inq,false,sizeof(inq));
memset(backid,-1,sizeof(backid));
for(int i=0;i<maxn;i++)
{
way[i] = -inf;
}
while(!q.empty())
{
q.pop();
}
q.push(0);
inq[0] = true;
way[0] = 0;
int now,to,temp,cost;
while(!q.empty())
{
now = q.front();
q.pop();
for(int i=0;i<g[now].size();i++)
{
if(g[now][i].c > 0)
{
to = g[now][i].to;
cost = g[now][i].cost;
temp = way[now] + cost;
if( temp > way[to] )
{
way[to] = temp;
backid[to] = g[now][i].id;
if(!inq[to])
{
inq[to] = true;
q.push(to);
}
}
}
}
inq[now] = false;
}
return ;
}
int change()
{
spfa();
int temp = end;
int id;
int from;
int fromid;
while(backid[temp] != -1)
{
id = backid[temp];
from = g[temp][id].to;
fromid = g[temp][id].id;
g[temp][id].c += 1;
g[from][fromid].c -= 1;
temp = from;
}
if(way[end] > 0)
{
return way[end];
}
else
{
return 0;
}
}
int ek()
{
build();
int ans = 0;
for(int i=1;i<=k;i++)
{
ans += change();
}
return ans;
}
int main()
{
while(cin>>n>>k)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cin>>a[i][j];
}
}
cout<<ek()<<endl;
}
return 0;
}