hdoj 3376 Matrix Again and hdoj 2686 Matrix 【最大费用最大流】

来源:互联网 发布:淘宝助理5.6.9 编辑:程序博客网 时间:2024/05/02 01:54



Matrix Again

Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others)
Total Submission(s): 3453    Accepted Submission(s): 1017


Problem Description
Starvae very like play a number game in the n*n Matrix. A positive integer number is put in each area of the Matrix.
Every time starvae should to do is that choose a detour which from the top left point to the bottom right point and than back to the top left point with the maximal values of sum integers that area of Matrix starvae choose. But from the top to the bottom can only choose right and down, from the bottom to the top can only choose left and up. And starvae can not pass the same area of the Matrix except the start and end..
Do you know why call this problem as “Matrix Again”? AS it is like the problem 2686 of HDU.
 

Input
The input contains multiple test cases.
Each case first line given the integer n (2<=n<=600) 
Then n lines, each line include n positive integers. (<100)
 

Output
For each test case output the maximal values starvae can get.
 

Sample Input
210 35 10310 3 32 5 36 7 1051 2 3 4 52 3 4 5 63 4 5 6 74 5 6 7 85 6 7 8 9
 

Sample Output
284680
 



无语死了,TLE到死。还好最后用G++卡过了,C++死活过不了。


两道题意一样,就是数据卡的不一样!!!

题意:给你一个N*N的矩阵,每个元素代表该处的权值。要求每个点只能走一次,左上角和右下角可以走两次但该处的权值只能获取一次。问你从左上角走到右下角(只能向下或右移动),再从右下角回到左上角(只能向上或左移动)所能得到的最大权值。


思路:把所有元素虚拟成N*N个点,把可达关系当做一条边,可走次数作为边的容量,权值当做边的费用。问题就变成了最大费用最大流。


建图:设置超级源点source,超级汇点sink

1,把所有点i拆分左点i 和 右点i + N*N,i到i+N*N建边,容量为1(只有当i为起点或者终点时容量才为2),费用为点权。

2,source连接左上角的左点,容量为2,费用0;

3,右下角右点连接sink,容量为2,费用0;

4,所有可达关系,即对于坐标(x, y) 向(x+1, y)和(x, y+1)建边(边界需要讨论),容量为1(至少1可以大于1),费用0。

最后跑一遍最大费用最大流后,减去起点权值和终点权值(我们多算了一次)就ok了。理解最小费用后求解最大费用很简单的,只需要把SPFA过程改为查找S-T的最大费用路径。


AC代码: 可以过这两个题


#include <cstdio>#include <cstring>#include <queue>#include <vector>#include <stack>#include <algorithm>#define MAXN 800000+10#define MAXM 4000000+10#define INF 0x3f3f3f3fusing namespace std;struct Edge{    int from, to, cap, flow, cost, next;};Edge edge[MAXM];int head[MAXN], edgenum;int pre[MAXN], dist[MAXN];bool vis[MAXN];int N;int Map[610][610];int source, sink;void init(){    edgenum = 0;    memset(head, -1, sizeof(head));}void addEdge(int u, int v, int w, int c){    edge[edgenum].from = u;    edge[edgenum].to = v;    edge[edgenum].cap = w;    edge[edgenum].flow = 0;    edge[edgenum].cost = c;    edge[edgenum].next = head[u];    head[u] = edgenum++;    edge[edgenum].from = v;    edge[edgenum].to = u;    edge[edgenum].cap = 0;    edge[edgenum].flow = 0;    edge[edgenum].cost = -c;    edge[edgenum].next = head[v];    head[v] = edgenum++;}int point(int x, int y){    return (x-1)*N + y;}void getMap(){    int k = N*N;    source = 0; sink = 2*k+1;    for(int i = 1; i <= N; i++)    {        for(int j = 1; j <= N; j++)        {            scanf("%d", &Map[i][j]);            if(i == 1 && j == 1 || i == N && j == N)                addEdge(point(i, j), point(i, j) + k, 2, Map[i][j]);//起点和终点 容量为2 费用为点权            else                addEdge(point(i, j), point(i, j) + k, 1, Map[i][j]);//左点连右点 容量为1 费用为点权            if(i < N)                addEdge(point(i, j)+k, point(i+1, j), 1, 0);//右点 连 左点 容量为1 费用0            if(j < N)                addEdge(point(i, j)+k, point(i, j+1), 1, 0);        }    }    addEdge(source, 1, 2, 0);//超级源点 连起点的左点 容量2 费用为0    addEdge(point(N, N)+k, sink, 2, 0);//终点的右点 连超级汇点 容量2 费用为0}bool SPFA(int s, int t){    queue<int> Q;    memset(dist, -INF, sizeof(dist));    memset(vis, false, sizeof(vis));    memset(pre, -1, sizeof(pre));    dist[s] = 0;    vis[s] = true;    Q.push(s);    while(!Q.empty())    {        int u = Q.front();        Q.pop();        vis[u] = false;        for(int i = head[u]; i != -1; i = edge[i].next)        {            Edge E = edge[i];            if(dist[E.to] < dist[u] + E.cost && E.cap > E.flow)//最大费用 且 无满流路径            {                dist[E.to] = dist[u] + E.cost;                pre[E.to] = i;                if(!vis[E.to])                {                    vis[E.to] = true;                    Q.push(E.to);                }            }        }    }    return pre[t] != -1;}void MCMF(int s, int t, int &cost, int &flow){    cost = flow = 0;    while(SPFA(s, t))    {        int Min = INF;        for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])        {            Edge E = edge[i];            Min = min(Min, E.cap-E.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(){    while(scanf("%d", &N) != EOF)    {        init();        getMap();        int cost, flow;        MCMF(source, sink, cost, flow);        cost -= Map[1][1] + Map[N][N];//多算了起点和终点的值        printf("%d\n", cost);    }    return 0;}



2 0