记得以前做过这样类似的题,因为那时候求的是来回的最大值,直接使用的dp,而且对费用流并不是很清楚,然后又看到了这道题。。。
对点进行拆分建图,一个点拆为两个点a和b,在a和b之间建一条花费为输入值容量为1的边,然后再建一条花费为0容量为k-1的边,对b点对于其右边和下边都建立一条容量为k花费为0的边,加入超级源点和汇点,花费为0容量为k,由此套模板就可以了!
下面是代码:
///////////////////////////////////////////////////////////////////////// // File Name: 2195.cpp // Author: wang // mail: [email protected] // Created Time: 2013/10/25 19:28:26 ///////////////////////////////////////////////////////////////////////// #include <cstdio> #include <cstdlib> #include <climits> #include <cstring> #include <cmath> #include <algorithm> #include<iostream> #include<queue> #include <map> using namespace std; typedef long long ll; #define INF (INT_MAX/10) #define SQR(x) ((x)*(x)) #define rep(i, n) for (int i=0; i<(n); ++i) #define repf(i, a, b) for (int i=(a); i<=(b); ++i) #define repd(i, a, b) for (int i=(a); i>=(b); --i) #define clr(ar,val) memset(ar, val, sizeof(ar)) #define inf 100000000 #define N 5010 class match{ public: //s和t要赋值的,并且花费一个为正一个为负刚好抵消的 int s,t;//源点和结束点的,开始为1 的 struct node{ int y,cost,cap,pre; }; node a[N*1000]; int dis[N]; bool vis[N]; int point[N]; int len,pre[N]; void init() { len=0; memset(pre,-1,sizeof(pre)); } void addpage(int x,int y,int cap,int cost) { a[len].y=y; a[len].pre=pre[x]; a[len].cap=cap; a[len].cost=cost; pre[x]=len++; } bool spfa() { repf(i,1,t) vis[i]=false,dis[i]=inf; vis[s]=true; dis[s]=0; queue<int>q; q.push(s); while(!q.empty()) { int x=q.front(); q.pop(); vis[x]=false; for(int i=pre[x]; i!=-1; i=a[i].pre) { int y=a[i].y; if(a[i].cap && dis[y]>dis[x]+a[i].cost) { point[y]=i;//记录边的 dis[y]=dis[x]+a[i].cost; if(vis[y]==false) { vis[y]=true; q.push(y); } } } } if(dis[t]!=inf) return true; else return false; } int fond() { int ans=0; while(spfa()) { int Min=INT_MAX; for(int i=t; i!=s; i=a[point[i]^1].y)//最小的容量,进行扩展的 Min=min(Min,a[point[i]].cap); for(int i=t; i!=s; i=a[point[i]^1].y) { a[point[i]].cap-=Min; a[point[i]^1].cap+=Min; ans+=Min*a[point[i]].cost; } } return -ans; } }; match sa; int a[55][55]; int n,m; int main() { while(scanf("%d%d",&n,&m)!=EOF) { repf(i,1,n) repf(j,1,n) scanf("%d",&a[i][j]); sa.init(); sa.s=0; sa.t=2*n*n+1; repf(i,1,n) repf(j,1,n) { int k=(i-1)*n+j;//2*k,2*k-1 sa.addpage(2*k-1,2*k,1,-a[i][j]); sa.addpage(2*k,2*k-1,0,a[i][j]); sa.addpage(2*k-1,2*k,m-1,0); sa.addpage(2*k,2*k-1,0,0); if(i<n) sa.addpage(2*k,2*(i*n+j)-1,m,0), sa.addpage(2*(i*n+j)-1,2*k,0,0); if(j<n) sa.addpage(2*k,2*(i*n-n+j+1)-1,m,0), sa.addpage(2*(i*n-n+j+1)-1,2*k,0,0); } sa.addpage(sa.s,1,m,0); sa.addpage(1,sa.s,0,0); sa.addpage(2*n*n,2*n*n+1,m,0); sa.addpage(2*n*n+1,2*n*n,0,0); printf("%d\n",sa.fond()); } return 0; }