题意:有个方阵,每个格子里都有一个非负数,从左上角走到右下角,每次走一步,只能往右或往下走,经过的数字拿走,换0
每次都找可以拿到数字和最大的路径走,走k次,求最大和
分析:最大费用最大流。因为点有权值,所以一般的做法是拆点,将一个点拆成两个点a和a',点的费用为权值,容量为1,然后再建一条边,边的费用为0,容量为INF,这样就能保证至少能通过这个点k次。。然后将a‘与右或下的点建一条边,边的费用为0,容量为INF..最后建一个超级源点和汇点,使之只能走k编。将超级源点与矩阵第一个点相连,费用为0,容量为k,超级汇点与矩阵最后一个点相连,费用为0,容量为k。这样,这个题的图就建完了。。
一开始手贱把if(j<n)打成if(j>n)了。。又调试了半天。。最大流题目不能手贱啊,手贱就跪了。。!!!
// File Name: 3422.cpp // author: zlbing // created time: 2013/3/3 22:17:43 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define CL(x,v); memset(x,v,sizeof(x)); #define INF 0x3f3f3f3f #define LL long long #define MAXN 50*50*2+10 #define REP(i,n) for(int i=0;i<n;i++) #define REP1(i,n) for(int i=1;i<n+1;i++) struct Edge{ int from,to,cap,flow,cost; }; struct MCMF{ int n,m,s,t; vector<Edge>edges; vector<int> G[MAXN]; int inq[MAXN]; int d[MAXN]; int p[MAXN]; int a[MAXN]; void init(int n){ this->n=n; for(int i=0;i<=n;i++)G[i].clear(); edges.clear(); } void AddEdge(int from,int to,int cap,int cost){ edges.push_back((Edge){from,to,cap,0,cost}); edges.push_back((Edge){to,from,0,0,-cost}); m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool BellmanFord(int s,int t,int& flow,int& cost){ for(int i=0;i<=n;i++)d[i]=INF; CL(inq,0); d[s]=0;inq[s]=1;p[s]=0;a[s]=INF; queue<int>Q; Q.push(s); while(!Q.empty()){ int u=Q.front();Q.pop(); inq[u]=0; for(int i=0;i<G[u].size();i++){ Edge& e=edges[G[u][i]]; if(e.cap>e.flow&&d[e.to]>d[u]+e.cost){ d[e.to]=d[u]+e.cost; p[e.to]=G[u][i]; a[e.to]=min(a[u],e.cap-e.flow); if(!inq[e.to]){ Q.push(e.to); inq[e.to]=1; } } } } if(d[t]==INF)return false; flow+=a[t]; cost+=d[t]*a[t]; int u=t; while(u!=s){ edges[p[u]].flow+=a[t]; edges[p[u]^1].flow-=a[t]; u=edges[p[u]].from; } return true; } int Mincost(int s,int t){ int flow=0,cost=0; while(BellmanFord(s,t,flow,cost)); return cost; } }; MCMF solver; int main(){ int n,k; while(~scanf("%d%d",&n,&k)) { int s=0; int t=2*n*n+1; solver.init(t); REP1(i,n){ REP1(j,n){ int tmp; scanf("%d",&tmp); solver.AddEdge(n*(i-1)+j,n*(i-1)+j+n*n,1,-tmp); solver.AddEdge(n*(i-1)+j,n*(i-1)+j+n*n,k-1,0); if(i<n) solver.AddEdge(n*(i-1)+j+n*n,n*i+j,INF,0); if(j<n) solver.AddEdge(n*(i-1)+j+n*n,n*(i-1)+j+1,INF,0); } } solver.AddEdge(s,1,k,0); solver.AddEdge(n*n*2,t,k,0); int ans=0; ans=-solver.Mincost(s,t); printf("%d\n",ans); } return 0; }