POJ3422 Kaka's Matrix Travels(费用流)

题意:给一个N*N的方阵,从[1,1]到[n,n]走K次,走过每个方格加上上面的数(每个方格初始都有一个非负数),然后这个格上面的数变为0。求可取得的最大的值。

思路:一开始以为是DP...囧...后来反应过来在做费用流的专题...这题很显然是把每个方阵的每个点当作顶点,连边求最大费用最大流,可是如果走过一次之后那个格子要变成0,不知道怎么处理,有一种很巧妙的处理,就是拆点。把每个点拆成i和i+n*n,两个拆出来的点之间连(i,i+n*n,1,-cost)和(i,i+n*n,INF,0),第一次知道还可以这样做..惊为天人..把一开始格子的数字通过拆点连一条容量为1的边,那么走过之后就不会再经过这条边了,走过之后变为0可以连一条容量为INF,表示可以随便走,费用为0,即可以让这个点的数值变为0了。另外题目要求的是最大值,那么可以将数字取反,那么用最小费用最大流求出来的再取反就是最大费用最大流了。

建图

          源点s编号0,n*n个网格每个网格分成两个点i和i+n*n, 汇点t编号为n*n*2+1.

          从源点s到1号节点有边(s , 1, K)

          从每个网格到自己有边(i, i+n*n, 1, -cost) 和(i, i+n*n, INF, 0) (注意这里的-cost,因为原题要我们求最大值)

          从每个网格i到它的右或下那个网格j有边(i+n*n, j, INF, 0)

          从最右下角到汇点t有边(2*n*n, t, INF, 0)

          最终我们求得的最小费用的绝对值就是权值最大值.

注意:不同点连边的时候要注意如果点在最下面和最右那排要判一下,因为已经没有后继了。


#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<vector>
#define INF 1e9
using namespace std;
const int maxn=5100;

struct Edge
{
    int from,to,cap,flow,cost;
    Edge(){}
    Edge(int f,int t,int c,int fl,int co):from(f),to(t),cap(c),flow(fl),cost(co){}
};

struct MCMF
{
    int n,m,s,t;
    vector<Edge> edges;
    vector<int> G[maxn];
    bool inq[maxn];     //是否在队列
    int d[maxn];        //Bellman_ford单源最短路径
    int p[maxn];        //p[i]表从s到i的最小费用路径上的最后一条弧编号
    int a[maxn];        //a[i]表示从s到i的最小残量

    //初始化
    void init(int n,int s,int t)
    {
        this->n=n, this->s=s, this->t=t;
        edges.clear();
        for(int i=0;i<n;++i) G[i].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 &flow, int &cost)
    {
        for(int i=0;i<n;++i) d[i]=INF;
        memset(inq,0,sizeof(inq));
        d[s]=0, a[s]=INF, inq[s]=true, p[s]=0;
        queue<int> Q;
        Q.push(s);
        while(!Q.empty())
        {
            int u=Q.front(); Q.pop();
            inq[u]=false;
            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]=true; }
                }
            }
        }
        if(d[t]==INF) return false;
        flow +=a[t];
        cost +=a[t]*d[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 Min_cost()
    {
        int flow=0,cost=0;
        while(BellmanFord(flow,cost));
        return cost;
    }
}mc;

int n,k;
int mapp[60][60];
int main()
{
    while (scanf("%d%d",&n,&k)!=EOF)
	{
		for (int i = 1;i<=n;i++)
		for (int j = 1;j<=n;j++)
			scanf("%d",&mapp[i][j]);
    	mc.init(2*n*n+2,0,2*n*n+1);
	    mc.AddEdge(0,1,k,0);
	    mc.AddEdge(n*n*2,n*n*2+1,INF,0);
	    for (int i = 1;i<=n;i++)
	    	for (int j = 1;j<=n;j++)
		    {
               int id = (i-1)*n+j;
		    	mc.AddEdge(id,id+n*n,1,-mapp[i][j]);
			   mc.AddEdge(id,id+n*n,INF,0);
			   if (i<=n-1)
			    	mc.AddEdge(id+n*n,id+n,INF,0);
		    	if (j<=n-1)
				mc.AddEdge(id+n*n,id+1,INF,0);
	    	}
	     printf("%d\n",-mc.Min_cost());
	}
} 

Description

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


你可能感兴趣的:(POJ3422 Kaka's Matrix Travels(费用流))