pku 3422 Kaka's Matrix Travels 最大费用最大流

http://poj.org/problem?id=3422

/*

题意:给定一个n*n的矩形方格,要求从(1,1)出发,只能往右下角走,(i + 1,j) 或者 (i + n,j)每次走完将格子里面的数累加,并将所走过的格子里面的数置零,问走k能得到的最大的数:

*/

/*

 网络流的题目建图是关键,这道题目建图很难想啊!首先要拆点。这里将一个点拆分成两个点,建立两条边,一条变得流量为1,权值为 map[i][j],另一条则是流量为无穷,权值为0了。注意这条边是为了保证在走过该店后,map[i][j]为0后,还能继续走因为它有流量且权值为0. 还有就是往右下角走建立流量为无穷权值为0的边。最后要建立的就是超级源点与汇点的边了,都是流量为k权值为0的边,保证走k次。

*/

code:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#define maxn 5005
using namespace std;

const int inf = 99999999;

struct node
{
    int u,v;
    int c,w;
    int next;
}g[maxn*100];
int head[maxn],cnt,pre[maxn];
int dis[maxn],map[maxn][maxn];
bool inq[maxn];
int n,m,k,s,t,ans;

//为静态表初始化
void init()
{
    memset(head,-1,sizeof(head));
    cnt = 0;
}
//加边,记住反向边去权值取反
void add(int u,int v,int c,int w)
{
    g[cnt].u = u; g[cnt].v = v; g[cnt].c = c; g[cnt].w = w;
    g[cnt].next = head[u]; head[u] = cnt++;

    g[cnt].u = v; g[cnt].v = u; g[cnt].c = 0; g[cnt].w = -w;
    g[cnt].next = head[v]; head[v] = cnt++;
}
void spfa()
{
    int i;
    queue<int>q;
    for (i = 0; i <= t; ++i)
    {
        dis[i] = -inf;
        inq[i] = false;
        pre[i] = -1;
    }
    q.push(s); inq[s] = true;
    dis[s] = 0;
    while (!q.empty())
    {
        int u = q.front(); q.pop();
        inq[u] = false;
        for (i = head[u]; i != -1; i = g[i].next)
        {
            int v = g[i].v;
            if (g[i].c && dis[v] < dis[u] + g[i].w)
            {
                dis[v] = dis[u] + g[i].w;
                pre[v] = i;//注意这里记录的是这一条边了
                if (!inq[v])
                {
                    inq[v] = true;
                    q.push(v);
                }
            }
        }
    }
}
void MCMF()
{
   while (1)
   {
       spfa();
       if (pre[t] == -1) break;
       int x = t,minf = inf;
       while (x != s)
       {
           minf = min(minf,g[pre[x]].c);
           x = g[pre[x]].u;
       }
       x = t;
       while (x != s)
       {
           g[pre[x]].c -= minf;
           g[pre[x]^1].c += minf;
           x = g[pre[x]].u;
       }
       ans += minf*dis[t];
   }
}
int main()
{
    int i,j;
    scanf("%d%d",&n,&k);
    int tmp = n*n;
    init();
    //关键是建边的过程
    for (i = 1; i <= n; ++i)
    {
        for (j = 1; j <= n; ++j)
        {
            scanf("%d",&map[i][j]);
            int x = (i - 1)*n + j;
            int y = x + tmp;
            add(x,y,1,map[i][j]);
            add(x,y,inf,0);
            if (i < n) add(y,x + n,inf,0);
            if (j < n) add(y,x + 1,inf,0);
        }
    }
    s = 0; t = 2*tmp + 1;
    add(s,1,k,0);
    add(2*tmp,t,k,0);
    ans = 0;
    MCMF();
    printf("%d\n",ans);
    return 0;
}

  

posted @ 2012-06-28 16:27  E_star  阅读(210)  评论(0编辑  收藏  举报