题目地址:POJ 3422
方法是对每个点i拆点成i'和i'',然后对每个i'和i''连一条费用为该点值,流量为1的边,再连1条费用为0,流量为k-1的边。
然后对每个点与右边下边相邻的点连边,流量均为INF,费用均为0。需要再建一源点与汇点,对于k次只需要在源点与汇点处进行限制即可。
代码如下:
#include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #include <ctype.h> #include <queue> #include <map> #include <set> #include <algorithm> using namespace std; const int INF=0x3f3f3f3f; const int maxn=6000; int head[maxn], source, sink, cnt, flow, cost, n; int d[maxn], vis[maxn], cur[maxn], f[maxn]; int mp[100][100]; struct node { int u, v, cap, cost, next; } edge[1000000]; void add(int u, int v, int cap, int cost) { edge[cnt].v=v; edge[cnt].cap=cap; edge[cnt].cost=cost; edge[cnt].next=head[u]; head[u]=cnt++; edge[cnt].v=u; edge[cnt].cap=0; edge[cnt].cost=-cost; edge[cnt].next=head[v]; head[v]=cnt++; } int spfa() { memset(vis,0,sizeof(vis)); memset(d,INF,sizeof(d)); deque<int>q; q.push_back(source); d[source]=0; cur[source]=-1; f[source]=INF; while(!q.empty()) { int u=q.front(); q.pop_front(); vis[u]=0; for(int i=head[u]; i!=-1; i=edge[i].next) { int v=edge[i].v; if(d[v]>d[u]+edge[i].cost&&edge[i].cap) { d[v]=d[u]+edge[i].cost; f[v]=min(f[u],edge[i].cap); cur[v]=i; if(!vis[v]) { if(!q.empty()&&d[v]<d[q.front()]) { q.push_front(v); } else q.push_back(v); vis[v]=1; } } } } if(d[sink]==INF) return 0; flow+=f[sink]; cost-=d[sink]*f[sink]; for(int i=cur[sink]; i!=-1; i=cur[edge[i^1].v]) { edge[i].cap-=f[sink]; edge[i^1].cap+=f[sink]; } return 1; } void mcmf() { flow=cost=0; while(spfa()) ; printf("%d\n",cost); } int main() { int i, j, k; scanf("%d%d",&n,&k); for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { scanf("%d",&mp[i][j]); } } memset(head,-1,sizeof(head)); cnt=0; source=0; sink=2*n*n+1; add(source,1,k,0); add(2*n*n,sink,k,0); for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { add((i-1)*n+j,(i-1)*n+j+n*n,1,-mp[i][j]); add((i-1)*n+j,(i-1)*n+j+n*n,k-1,0); if(i+1<=n) { add((i-1)*n+j+n*n,i*n+j,k,0); } if(j+1<=n) { add((i-1)*n+j+n*n,(i-1)*n+j+1,k,0); } } } mcmf(); return 0; }