POJ 3422 【最大费用】.cpp

题意:

给出一个每一格带值的矩阵

每一次只可以从左上角走到右下角

问走过k次后最多能得到多少值

P.S 走过的格子值会变成0

输入:

  给出一个n 和 k

  给出n*n 矩阵

 

思路:

  因为求的是最大值

  所以应该求最长距离..把最小路径改成求最大路径

  <相应改变的就是松弛操作 和 dis的初始状态>

  

  为了保证每个点只取一次值 并且 可以经过多次

  就进行拆点 然后对应点之间加两条边 ①. 容量为1 费用为该点的值 ②. 容量为INF 费用为0

  ①边保证了该点走过后变为0值 ②边保证该点可以经过多次

 

  还有超级源点跟每个点之间连边 容量为k 费用为0

  超级汇点和每个拆点之间连边 容量为k 费用为0

 

Tips:

  加边的时候记得判断边界情况..

  还有因为拆点了 和 加了超级源点和汇点  边数就要相应增多..

  循环队列也要开大点..  

 

Code:

 

View Code
  1 #include <stdio.h>
  2 #include <cstring>
  3 #include <algorithm>
  4 using namespace std;
  5 #define clr(x) memset(x, 0, sizeof(x))
  6 const int INF = 0x1f1f1f1f;
  7 const int MAXN = 6000;
  8 const int MAXM = 100010;
  9 struct Edge
 10 {
 11     int from;
 12     int to;
 13     int next;
 14     int c;
 15     int f;
 16 }edge[MAXM];
 17 int head[MAXN];
 18 int tot;
 19 int n, k;
 20 int dis[MAXN], pre[MAXN];
 21 bool flag[MAXN];
 22 
 23 void add(int s, int u, int c, int f)
 24 {
 25     edge[tot].from = s;
 26     edge[tot].to = u;
 27     edge[tot].next = head[s];
 28     edge[tot].f = f;
 29     edge[tot].c = c;
 30     head[s] = tot++;
 31 
 32     edge[tot].from = u;
 33     edge[tot].to = s;
 34     edge[tot].f = 0;
 35     edge[tot].c = -c;
 36     edge[tot].next = head[u];
 37     head[u] = tot++;
 38 }
 39 
 40 int que[MAXN*100];
 41 bool spfa(int s, int e)
 42 {
 43     int qout, qin;
 44     clr(flag);
 45     memset(pre, 0xff, sizeof(pre));
 46     memset(dis, 0xff, sizeof(dis));
 47     qin = qout = 0;
 48     que[qin++] = s;
 49     dis[s] = 0;
 50     flag[s] = true;
 51     while(qin != qout) {
 52         int tmpe = que[qout++];
 53         flag[tmpe] = false;
 54         for(int i = head[tmpe]; i != -1; i = edge[i].next) {
 55             int ne = edge[i].to;
 56             if(edge[i].f && dis[ne]-dis[tmpe] < edge[i].c) {
 57                 dis[ne] = dis[tmpe]+edge[i].c;
 58                 pre[ne] = i;
 59                 if(!flag[ne]) {
 60                     flag[ne] = true;
 61                     que[qin++] = ne;
 62                 }
 63             }
 64         }
 65     }
 66 
 67     if(dis[e] == -1)
 68         return false;
 69     else return true;
 70 }
 71 
 72 int min_c_f(int s, int e)
 73 {
 74     int u, mn;
 75     int ans_f = 0, ans_c = 0;
 76     while(spfa(s, e))
 77     {
 78         u = pre[e];
 79         mn = INF;
 80         while(u != -1) {
 81             mn = min(edge[u].f, mn);
 82             u = pre[edge[u].from];
 83         }
 84         u = pre[e];
 85         while(u != -1) {
 86             edge[u].f -= mn;
 87             edge[u^1].f += mn;
 88             u = pre[edge[u].from];
 89         }
 90         ans_c += dis[e]*mn;
 91         ans_f += mn;
 92     }
 93     return ans_c;
 94 }
 95 
 96 int main()
 97 {
 98     int i, j;
 99     int w, t;
100     while(scanf("%d %d", &n, &k) != EOF)
101     {
102         tot = 0, t = n*n;
103         memset(head, 0xff, sizeof(head));
104         clr(flag), clr(dis), clr(pre);
105 
106         for(i = 1; i <= t; ++i) {
107             scanf("%d", &w);
108             add(i, i+t, w, 1);
109             add(i, i+t, 0, INF);
110             if(i%n != 0)
111                 add(i+t, i+1, 0, INF);
112             if(i <= t-n)
113                 add(i+t, i+n, 0, INF);
114         }
115 
116         add(0, 1, 0, k);
117         add(2*t, 2*t+1, 0, k);
118         int ans = min_c_f(0, 2*t+1);
119         printf("%d\n", ans);
120     }
121     return 0;
122 }

 

 

 

题目链接:http://poj.org/problem?id=3422

posted @ 2012-10-02 20:54  Griselda.  阅读(225)  评论(0编辑  收藏  举报