【POJ - 3422】Kaka's Matrix Travels【拆点费用流+经典建图】

xiaoxiao2021-02-28  37

On an N × N chessboard with a non-negative number in each grid, Kaka starts his matrix travels with SUM = 0. For each travel, Kaka moves one rook from the left-upper grid to the right-bottom one, taking care that the rook moves only to the right or down. Kaka adds the number to SUM in each grid the rook visited, and replaces it with zero. It is not difficult to know the maximum SUM Kaka can obtain for his first travel. Now Kaka is wondering what is the maximum SUM he can obtain after his Kth travel. Note the SUM is accumulative during the K travels.

Input The first line contains two integers N and K (1 ≤ N ≤ 50, 0 ≤ K ≤ 10) described above. The following N lines represents the matrix. You can assume the numbers in the matrix are no more than 1000.

Output The maximum SUM Kaka can obtain after his Kth travel.

Sample Input 3 2 1 2 3 0 2 1 1 4 2 Sample Output 15 题意 :一个矩阵,每个位置上有点权,让你现在从左上角运动到右下角 走k次,每个点可以走多次,但是每个位置的点权只可以获得一次。问k次之后得到的最大的值。

分析 :我喜欢这样用矩阵来建图的题,很有感觉。HDU的这个题的变形 这两个题目,我都是用的拆点,拆的两个点之间的边来表示经过这个点获得的分数。 下面看图【图画的有点乱,TAT】 总共需要将n*n个点进行拆点,图中我假设从起点到终点之间只有一个点。 S->1的边流量为k,表明可以走k次旅行,费用为0。 1 -> 1’ 2 -> 2’ 等等即图中的绿色的边,其流量为1,费用为1 . 2. 等等位置的权值, 意思就是如果要经过这个边就 表明是获得这个位置的分数,流量限制为1表示只能够获得一次分数。 1->2 边流量为inf,费用为0,表明可以从1走到2但是不获得分数。 2->3同上理。 1’-> 2 流量为inf,费用为0,表明获得完1分数之后仍然可以走到2这个点。 2 ’ -> 3 同上理。 3->T 和3’->T 流量都为inf,费用为0,分别表明可以不获得分数到达终点的旅行,获得分数仍然可以到达终点的旅行。 一条流就代表一个旅行。 代码

#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<queue> using namespace std; #define LL long long #define fread() freopen("in.txt","r",stdin) #define fwrite() freopen("out.txt","w",stdout) #define CLOSE() ios_base::sync_with_stdio(false) const int MAXN = 6000+11; const int MAXM = 500000+11; const int mod = 1e9+7; const int inf = 0x3f3f3f3f; struct Edge { int from,to,next,cap,flow,cost; }edge[MAXM]; int head[MAXN],top; void init(){ memset(head,-1,sizeof(head)); top=0; } void addedge(int a,int b,int w,int c){ edge[top].from=a,edge[top].to=b,edge[top].cap=w,edge[top].flow=0,edge[top].cost=c,edge[top].next=head[a]; head[a]=top++; edge[top].from=b,edge[top].to=a,edge[top].cap=0,edge[top].flow=0,edge[top].cost=-c,edge[top].next=head[b]; head[b]=top++; } int n,k,m; int S,T; int mp[55][55]; void getmap(){ S=0,T=n*m*2+1; int temp=n*m; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%d",&mp[i][j]); } } addedge(S,1,k,0); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ addedge((i-1)*n+j,(i-1)*n+j+temp,1,-mp[i][j]);//自己和对称的自己的边 int nx=i+1;int ny=j; if(nx<1||ny<1||nx>n||ny>m) ; else { addedge(((i-1)*n+j),(nx-1)*n+ny,inf,0);// 不获得分数也可以到达的路 addedge(((i-1)*n+j)+temp,(nx-1)*n+ny,inf,0);//获得分数仍然可以到达的路 } nx=i;ny=j+1; if(nx<1||ny<1||nx>n||ny>m) ; else { addedge(((i-1)*n+j),(nx-1)*n+ny,inf,0); addedge(((i-1)*n+j)+temp,(nx-1)*n+ny,inf,0); } } } addedge(n*m,T,inf,0); //不获得分数也可以到达终点的路 addedge(n*m+temp,T,inf,0);/、获得分数也可以到达终点的路 } bool vis[MAXN];int dis[MAXN]; int pre[MAXN]; bool spfa(int s,int e){ queue<int>Q; memset(vis,0,sizeof(vis)); memset(dis,0x3f,sizeof(dis)); memset(pre,-1,sizeof(pre)); dis[s]=0;vis[s]=1;Q.push(s); while(!Q.empty()){ int now=Q.front();Q.pop();vis[now]=0; for(int i=head[now];i!=-1;i=edge[i].next){ Edge e=edge[i]; if(e.cap>e.flow&&dis[e.to]>dis[now]+e.cost){ dis[e.to]=dis[now]+e.cost; pre[e.to]=i; if(!vis[e.to]){ vis[e.to]=1; Q.push(e.to); } } } } return pre[e]!=-1; } int MCMF(int s,int t,int &cost,int &flow){ flow=cost=0; while(spfa(s,t)){ int Min=inf; for(int i=pre[t];i!=-1;i=pre[edge[i^1].to]){ Min=min(Min,edge[i].cap-edge[i].flow); } for(int i=pre[t];i!=-1;i=pre[edge[i^1].to]){ edge[i].flow+=Min; edge[i^1].flow-=Min; cost+=edge[i].cost*Min; } flow+=Min; } } int main(){ CLOSE(); // fread(); // fwrite(); while(scanf("%d%d",&n,&k)!=EOF){ init(); m=n; getmap(); int flow,ans; MCMF(S,T,ans,flow); //printf("%d\n",flow); printf("%d\n",-ans); } return 0; }
转载请注明原文地址: https://www.6miu.com/read-2150053.html

最新回复(0)