zkw费用流,可以在残余网络上跑。
注意这里的 maxflow 和 mincost 没有在 MFMC 中初始化
还有这里 反向边的存储 通过 op 记录,不可以通过 ^ 操作实现。
#include <bits/stdc++.h>
using namespace std;
typedef int lint;
const int maxn = 25;
const int inf = 0x3f3f3f3f;
vector<int> e1,e2;
int S,T;
namespace MFMC{
const int N = 505;
const int M = 100005;
const lint inf = 0x3f3f3f3f;
struct edge {
int from,to,c,op,next;
lint w;
} e[M];
int vis[N],last[N],tot;
lint dis[N];
int s,t;
void add(int u,int v,int c,lint w) {
e[++tot].from=u;
e[tot].to=v;
e[tot].c=c;
e[tot].w=w;
e[tot].op=tot+1;
e[tot].next=last[u];
last[u]=tot;
if( u == S ){
e1.push_back( tot );
}
if( v == T ){
e2.push_back( tot );
}
e[++tot].from=v;
e[tot].to=u;
e[tot].c=0;
e[tot].w=-w;
e[tot].op=tot-1;
e[tot].next=last[v];
last[v]=tot;
if( u == S ){
e1.push_back( tot );
}
if( v == T ){
e2.push_back( tot );
}
}
void init( int n ) {
tot = 0;
memset( vis,0,sizeof(lint)*(n+1) );
memset( dis,0,sizeof(lint)*(n+1) );
memset( last,0,sizeof(lint)*(n+1) );
}
int dfs(int x,lint maxf,lint& mincost) {
if (x==t||maxf==0) return maxf;
lint ret=0;
vis[x]=1;
for (int i=last[x]; i; i=e[i].next)
if (e[i].c&&dis[e[i].to]+e[i].w==dis[x]&&!vis[e[i].to]) {
lint f=dfs(e[i].to,min(e[i].c,maxf-ret),mincost);
mincost+=f*e[i].w;
e[i].c-=f;
e[e[i].op].c+=f;
ret+=f;
if (ret==maxf) break;
}
return ret;
}
bool change() {
lint mn=inf;
for (int i=0; i<=t; i++)
if (vis[i])
for (int j=last[i]; j; j=e[j].next)
if (!vis[e[j].to]&&e[j].c) mn=min(mn,-dis[i]+e[j].w+dis[e[j].to]);
if (mn==inf) return 0;
for (int i=0; i<=t; i++)
if (vis[i]) dis[i]+=mn;
return 1;
}
void zkw( int _s,int _t,lint& maxflow,lint& mincost ) {
s = _s; t = _t;
do {
for (int i=0; i<=t; i++) vis[i]=0;
lint dt = 0;
while ( dt = dfs(s,inf,mincost)) {
maxflow += dt;
for (int i=0; i<=t; i++) vis[i]=0;
}
} while (change());
}
}
int a[maxn][maxn];
int gcd( int x,int y ){
if( !y ) return x;
return gcd( y,x%y );
}
int main(){
int ca,tt = 0;
scanf("%d",&ca);
while(ca--){
e1.clear();e2.clear();
int n,m,res = 0;
scanf("%d%d",&n,&m);
int lcm = n*m/gcd(n,m);
for( int i = 1;i <= n;i++ ){
for( int j = 1;j <= m;j++ ){
scanf("%d",&a[i][j]);
res += a[i][j];
}
}
S = 0,T = 50;
MFMC::init(T);
int ans = inf;
int hi = 20*n*m;
for( int i = 1;i <= n;i++ ){
for( int j = 1;j <= m;j++ ){
MFMC::add( i,j+20,a[i][j],-1 );
MFMC::add( i,j+20,inf,1 );
}
}
for( int i = 1;i <= n;i++ ){
MFMC::add( S,i,0,0 );
}
for( int i = 1;i <= m;i++ ){
MFMC::add( i+20,T,0,0 );
}
int mincost = 0,maxflow =0 ;
for( int c = 0;c <= hi;c += lcm ){
if(c) {
for (int i :e1 ) {
MFMC::e[i].c += lcm/n;
}
for (int i :e2 ) {
MFMC::e[i].c += lcm/m;
}
}
MFMC::zkw( S,T,maxflow,mincost );
ans = min( ans,res+mincost );
}
printf("Case %d: %d\n",++tt,ans);
}
return 0;
}
下面是普通zkw不在残余网络上跑 的TLE版本,不过更适合作为模板
mincost 和 maxflow 都在MFMC中清空了。
#include <bits/stdc++.h>
using namespace std;
typedef int lint;
const int maxn = 25;
const int inf = 0x3f3f3f3f;
int S,T;
namespace MFMC{
const int N = 505;
const int M = 100005;
const lint inf = 0x3f3f3f3f;
struct edge {
int from,to,c,op,next;
lint w;
} e[M];
int vis[N],last[N],tot;
lint dis[N];
int s,t;
void add(int u,int v,int c,lint w) {
e[++tot].from=u;
e[tot].to=v;
e[tot].c=c;
e[tot].w=w;
e[tot].op=tot+1;
e[tot].next=last[u];
last[u]=tot;
e[++tot].from=v;
e[tot].to=u;
e[tot].c=0;
e[tot].w=-w;
e[tot].op=tot-1;
e[tot].next=last[v];
last[v]=tot;
}
void init( int n ) {
tot = 0;
memset( vis,0,sizeof(lint)*(n+1) );
memset( dis,0,sizeof(lint)*(n+1) );
memset( last,0,sizeof(lint)*(n+1) );
}
int dfs(int x,lint maxf,lint& mincost) {
if (x==t||maxf==0) return maxf;
lint ret=0;
vis[x]=1;
for (int i=last[x]; i; i=e[i].next)
if (e[i].c&&dis[e[i].to]+e[i].w==dis[x]&&!vis[e[i].to]) {
lint f=dfs(e[i].to,min(e[i].c,maxf-ret),mincost);
mincost+=f*e[i].w;
e[i].c-=f;
e[e[i].op].c+=f;
ret+=f;
if (ret==maxf) break;
}
return ret;
}
bool change() {
lint mn=inf;
for (int i=0; i<=t; i++)
if (vis[i])
for (int j=last[i]; j; j=e[j].next)
if (!vis[e[j].to]&&e[j].c) mn=min(mn,-dis[i]+e[j].w+dis[e[j].to]);
if (mn==inf) return 0;
for (int i=0; i<=t; i++)
if (vis[i]) dis[i]+=mn;
return 1;
}
void zkw( int _s,int _t,lint& maxflow,lint& mincost ) {
s = _s; t = _t;
mincost = maxflow = 0;
do {
for (int i=0; i<=t; i++) vis[i]=0;
lint dt = 0;
while ( dt = dfs(s,inf,mincost)) {
maxflow += dt;
for (int i=0; i<=t; i++) vis[i]=0;
}
} while (change());
}
}
int a[maxn][maxn];
int gcd( int x,int y ){
if( !y ) return x;
return gcd( y,x%y );
}
int main(){
int ca,tt = 0;
scanf("%d",&ca);
while(ca--){
int n,m,res = 0;
scanf("%d%d",&n,&m);
int lcm = n*m/gcd(n,m);
for( int i = 1;i <= n;i++ ){
for( int j = 1;j <= m;j++ ){
scanf("%d",&a[i][j]);
res += a[i][j];
}
}
S = 0,T = 50;
int ans = inf;
int hi = 20*n*m;
int mincost = 0,maxflow =0 ;
for( int c = 0;c <= hi;c += lcm ){
MFMC::init(T);
for( int i = 1;i <= n;i++ ){
for( int j = 1;j <= m;j++ ){
MFMC::add( i,j+20,a[i][j],-1 );
MFMC::add( i,j+20,inf,1 );
}
}
for( int i = 1;i <= n;i++ ){
MFMC::add( S,i,c/n,0 );
}
for( int i = 1;i <= m;i++ ){
MFMC::add( i+20,T,c/m,0 );
}
MFMC::zkw( S,T,maxflow,mincost );
ans = min( ans,res+mincost );
}
printf("Case %d: %d\n",++tt,ans);
}
return 0;
}