VEXOBEN
Vexoben
Nov 25, 2017
It takes 8 minutes to read this article.

题目链接:http://codevs.cn/problem/1227

周六zrf要讲网络流啊,像我这种蒟蒻不预习一下肯定全程掉线。

题解

首先是一种建模的思想:将每个点拆成出入两个点。

取k次,相当于流出一条大小为k的流。流过一个点即将这个点的数取走。

因为每个点可以流经多次,但只能产生一次贡献,所以我们从所有入点向所有出点连一条容量为1的边,价值为点的权值。然后将出入点都向右边和下方的点的入点连一条容量为inf,价值为0的边,跑最小费用最大流即可。

几个细节:

1、有两个源点两个汇点。建立超级源汇点即可。注意(n,n)的入点到汇点容量应为k-1,出点到汇点容量为1。

2、要求的实际是最大费用。将所有边费用取反即可。

3、STL的dequeue好慢啊手写一个

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<time.h>
#include<vector>
#include<cstring>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int N=1e5+10;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;

int n,m,k,s,t,V,E=1,cost,a[51][51];
int fir[N],len[N],dis[N],nex[N],arr[N],vis[N],cap[N];
struct Dequeue{
	int head,tail,num[N<<1];
	inline void Init() {head=N-1,tail=N;}
	inline int size() {return head-tail+1;}
	inline void push_front(int x) {num[++head]=x;}
	inline void push_back(int x) {num[--tail]=x;}
	inline void pop_front() {--head;}
	inline void pop_back() {++tail;}
	inline int front() {return num[head];}
	inline int back() {return num[tail];}
}q;

inline void read(int &x) {
	int f=1; x=0;
	register char c=getchar();
	for (;(c!='-')&&(c<'0'||c>'9');) c=getchar();
	if (c=='-') f=-1,c=getchar();
	for (;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
	x*=f;
}

inline void Add_Edge(int x,int y,int c,int l) {
	nex[++E]=fir[x];
	fir[x]=E; arr[E]=y;
	len[E]=l; cap[E]=c;
	nex[++E]=fir[y];
	fir[y]=E; arr[E]=x;
	len[E]=-l; cap[E]=0;
}

inline void Build_Graph() {
	V=1;
	Add_Edge(1,2,k,0);
	for (int i=1;i<=n;++i)
		for (int j=1;j<=n;++j) {
			V+=2;
			Add_Edge(V-1,V,1,-a[i][j]);
			if (j!=n) {
				Add_Edge(V-1,V+1,inf,0);
				Add_Edge(V,V+1,inf,0);
			}
			if (i!=n) {
				Add_Edge(V-1,V+2*n-1,inf,0);
				Add_Edge(V,V+2*n-1,inf,0);
			}
		}
	Add_Edge(V-1,V+1,k-1,0);
	Add_Edge(V,V+1,1,0);
	++V;
}

inline int Spfa() {
	q.Init();
	memset(vis,0,sizeof(int)*(V+5));
	memset(dis,0x3f,sizeof(int)*(V+5));
	dis[t]=0; q.push_front(t);
	while (q.size()) {
		int u=q.front(); q.pop_front();
		vis[u]=0;
		for (int i=fir[u];i;i=nex[i]) {
			if (!cap[i^1]) continue;
			int v=arr[i];
			if (dis[v]>dis[u]+len[i^1]) {
				dis[v]=dis[u]+len[i^1];
				if (!vis[v]) {
					vis[v]=1;
					if (dis[q.front()]>dis[v]) q.push_front(v);
					else q.push_back(v);
				}
			}
		}
	}
	return dis[s]<inf;
}

inline int Dfs(int x,int maxflow) {
	vis[x]=1;
	if (x==t||!maxflow) return maxflow;
	int ans=0;
	for (int i=fir[x];i;i=nex[i]) {
		if(cap[i]&&!vis[arr[i]]&&dis[x]==dis[arr[i]]+len[i]) {
			int del=Dfs(arr[i],min(maxflow,cap[i]));
			maxflow-=del;
			ans+=del; cost+=del*len[i];
			cap[i]-=del; cap[i^1]+=del;	
		}
	}
	return ans;
}

int main() {
	read(n); read(k);
	for (int i=1;i<=n;++i)
		for (int j=1;j<=n;++j)
			read(a[i][j]);
	Build_Graph();
	s=1,t=V;
	while (Spfa()) {
		do {
			memset(vis,0,sizeof(int)*(V+10));
			Dfs(s,inf);
		}while (vis[t]);
	}
	printf("%d",-cost);
	return 0;
}