0
点赞
收藏
分享

微信扫一扫

POJ3422简单费用流

夏沐沐 2022-07-27 阅读 45

题意:
     给一个n*n的矩阵,从左上角走到右下角,的最大收益,可以走k次,每个格子的价值只能取一次,但是可以走多次。


思路:
      比较简单的一个费用流题目,直接拆点,拆开的点之间连接两条边,一条是流量1费用是这个点的价值,另一条是流量k-1费用是0,然后就是当前这个点连接右下方的点,然后在虚拟出超级远点和汇点限流用的,比较简单,不解释了。

#include<stack>

#include<queue>

#include<stdio.h>

#include<string.h>



#define N_node 5100

#define N_edge 200000

#define INF 1000000000



using namespace std;



typedef struct

{

int from ,to ,cost ,flow ,next;

}STAR;



STAR E[N_edge];

int list[N_node] ,tot;

int s_x[N_node] ,mer[N_node];



void add(int a ,int b ,int c ,int d)

{

E[++tot].from = a;

E[tot].to = b;

E[tot].cost = c;

E[tot].flow = d;

E[tot].next = list[a];

list[a] = tot;



E[++tot].from = b;

E[tot].to = a;

E[tot].cost = -c;

E[tot].flow = 0;

E[tot].next = list[b];

list[b] = tot;



}



bool spfa(int s ,int t ,int n)

{

for(int i = 0 ;i <= n ;i ++)

s_x[i] = -INF;

int mark[N_node] = {0};

queue<int>q;

q.push(s);

s_x[s] = 0;

mark[s] = 1;

memset(mer ,255 ,sizeof(mer));

while(!q.empty())

{

int xin ,tou;

tou = q.front();

q.pop();

mark[tou] = 0;

for(int k = list[tou] ;k ;k = E[k].next)

{

xin = E[k].to;

if(s_x[xin] < s_x[tou] + E[k].cost && E[k].flow)

{

s_x[xin] = s_x[tou] + E[k].cost;

mer[xin] = k;

if(!mark[xin])

{

mark[xin] = 1;

q.push(xin);

}

}



}

}

return mer[t] != -1;

}



int M_M_Flow(int s ,int t ,int n)

{

int maxflow = 0 ,maxcost = 0 ,minflow;

while(spfa(s ,t ,n))

{

minflow = INF;

for(int i = mer[t] ;i + 1 ;i = mer[E[i].from])

if(minflow > E[i].flow) minflow = E[i].flow;

for(int i = mer[t] ;i + 1 ;i = mer[E[i].from])

{

E[i].flow -= minflow;

E[i^1].flow += minflow;

maxcost += minflow * E[i].cost;

}

maxflow += minflow;

}

return maxcost;

}



int main ()

{

int n ,k ,i ,j ,Ans ,num;

while(~scanf("%d %d" ,&n ,&k))

{

memset(list ,0 ,sizeof(list)) ,tot = 1;

for(i = 1 ;i <= n ;i ++)

for(j = 1 ;j <= n ;j ++)

{

scanf("%d" ,&num);

add((i - 1) * n + j ,(i - 1) * n + j + n * n ,num ,1);

add((i - 1) * n + j ,(i - 1) * n + j + n * n ,0 ,k - 1);

}



add(0 ,1 ,0 ,k);

for(i = 1 ;i <= n ;i ++)

for(j = 1 ;j <= n ;j ++)

{

if(i <= n - 1) add((i - 1) * n + j + n * n ,i * n + j ,0 ,k);

if(j <= n - 1) add((i - 1) * n + j + n * n ,(i - 1) * n + j + 1 ,0 ,k);

}

add(n * n * 2 ,n * n * 2 + 1 ,0 ,k);

Ans = M_M_Flow(0 ,n * n * 2 + 1 ,n * n * 2 + 1);

printf("%d\n" ,Ans);

}

return 0;

}














举报

相关推荐

0 条评论