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

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

2
10 3
5 10
3
10 3 3
2 5 3
6 7 10
5
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
5 6 7 8 9

Sample Output

28
46
80

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

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

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

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

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

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

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

3,右下角右点连接source,容量为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 0x3f3f3f3f
using 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 sink, source;
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;
    sink = 0; source = 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(sink, 1, 2, 0);//超级源点 连起点的左点 容量2 费用为0
    addEdge(point(N, N)+k, source, 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(sink, source, cost, flow);
        cost -= Map[1][1] + Map[N][N];//多算了起点和终点的值
        printf("%d\n", cost);
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-29 15:31:38

hdoj 3376 Matrix Again and hdoj 2686 Matrix 【最大费用最大流】的相关文章

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

题目:hdoj 3376 Matrix Again 题意:给出一个m*n的矩阵,然后从左上角到右下角走两次,每次只能向右或者向下,出了末尾点其他只能走一次,不能交叉,每次走到一个格子拿走这个格子中的数字,求价值最大? 分析:很明显费用流,开始想的到一种建图方案,但是那样的话流量全为负值的话会成一个环,所以果断换了. 建图方案是: 首先拆点,每个点拆成两个i 和 ii ,建边,费用为当前格子的值,流量为1,初始点和末尾点为2 然后每个点向它的右边和下边分别建边,容量为1,费用为0 s 连接 左上角

HDOJ 3376 Matrix Again

和HDOJ 2686 一样,只是范围不同 最大费用最大流..... 与最小费用最大流的区别用////////////标出来了 对于detour,在源点和汇点处的边的流量为2 对于每个点只能经过一次,拆点,两个点直接建一条流量为1,费用为mp[i][j]的边 对于每个点可以走到他的左边和下边:连一个费用为0流量大于1的边 Matrix Again Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 102400/102400 K (Jav

POJ 2135 Farm Tour &amp;&amp; HDU 2686 Matrix &amp;&amp; HDU 3376 Matrix Again 费用流求来回最短路

累了就要写题解,最近总是被虐到没脾气. 来回最短路问题貌似也可以用DP来搞,不过拿费用流还是很方便的. 可以转化成求满流为2 的最小花费.一般做法为拆点,对于 i 拆为2*i 和 2*i+1,然后连一条流量为1(花费根据题意来定) 的边来控制每个点只能通过一次. 额外添加source和sink来控制满流为2. 代码都雷同,以HDU3376为例. #include <algorithm> #include <iostream> #include <cstring> #in

HDU 2686 Matrix 3376 Matrix Again(费用流)

HDU 2686 Matrix 题目链接 3376 Matrix Again 题目链接 题意:这两题是一样的,只是数据范围不一样,都是一个矩阵,从左上角走到右下角在从右下角走到左上角能得到最大价值 思路:拆点,建图,然后跑费用流即可,不过HDU3376这题,极限情况是300W条边,然后卡时间过了2333 代码: #include <cstdio> #include <cstring> #include <vector> #include <queue> #i

hdu 2686 Matrix &amp;&amp; hdu 3367 Matrix Again (最大费用最大流)

Matrix Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1394    Accepted Submission(s): 758 Problem Description Yifenfei very like play a number game in the n*n Matrix. A positive integer number

HDU 2686 Matrix(最大费用最大流+拆点)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2686 和POJ3422一样 删掉K把汇点与源点的容量改为2(因为有两个方向的选择)即可 #include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> const int ma

hdu 2686 Matrix 最小费用最大流

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2686 Yifenfei 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 yifenfei should to do is that choose a detour which frome the top left

Matrix Again(最大费用最大流)

Matrix Again Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 102400/102400 K (Java/Others) Total Submission(s): 16 Accepted Submission(s): 7   Problem Description Starvae very like play a number game in the n*n Matrix. A positive integer number

ACdream-1171 Matrix sum, 最大费用最大流

Matrix sum Time Limit: 8000/4000MS (Java/Others)Memory Limit: 128000/64000KB (Java/Others) SubmitStatisticNext Problem Problem Description sweet和zero在玩矩阵游戏,sweet画了一个N * M的矩阵,矩阵的每个格子有一个整数.zero给出N个数Ki,和M个数Kj,zero要求sweet选出一些数,满足从第 i 行至少选出了Ki个数,第j列至少选出了K