HDU2686-Matrix & HDU3376-Matrix Again(费用流)

比较简单的题了。

只需从左上角到右下角找两条路就可以了。

因为每个点只能走一次,所以拆点,限制流量为1。

因为求的是最大值,所以权值取反求最小值。

因为第一个点和最后一个点经过两次,只算一次,最后要减去。

ps:数组还是开大点好。。。。不知道什么时候就SB了。。。

注意汇点可能不是最后一个点(模板的问题。。

注意初始化的范围。。。。

matrix again只是数据大了,算法不用改。。。无聊。。。。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <bitset>
#include <cstdio>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <map>
#include <set>
#define pk(x) printf("%d\n", x)
using namespace std;
#define PI acos(-1.0)
#define EPS 1E-6
#define clr(x,c) memset(x,c,sizeof(x))
//#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;

const int MAXV = 2000;
const int INF = 1<<30;

struct Edge { int to, cap, cost, rev; };
vector<Edge> G[MAXV];
int dist[MAXV], prv[MAXV], pre[MAXV], in[MAXV];
queue<int> que;

void addedge(int from, int to, int cap, int cost) {
    G[from].push_back((Edge){to, cap, cost, G[to].size()});
    G[to].push_back((Edge){from, 0, -cost, G[from].size()-1});
}

int min_cost_max_flow(int s, int t) { //, int f) {
    int res = 0;
    int f = 0;
    while (1) { //f > 0) {
        for (int i = 1; i <= t; ++i) dist[i] = INF, in[i] = 0;
        dist[s] = 0;
        while (!que.empty()) que.pop();
        in[s] = 1;
        que.push(s);

        while (!que.empty()) {
            int u = que.front(); que.pop(); in[u] = 0;
            for (int i = 0; i < G[u].size(); ++i) {
                Edge &e = G[u][i];
                if (e.cap > 0 && dist[e.to] > dist[u] + e.cost) {
                    dist[e.to] = dist[u] + e.cost;

                    prv[e.to] = u;
                    pre[e.to] = i;
                    if (in[e.to] == 0) {
                        in[e.to] = 1;
                        que.push(e.to);
                    }
                }
            }
        }

        if (dist[t] == INF) break; //return -1;

        int d = INF; // d = f;
        for (int v = t; v != s; v = prv[v]) {
            d = min(d, G[prv[v]][pre[v]].cap);
        }
        f += d;
        res += d * dist[t];
        for (int v = t; v != s; v = prv[v]) {
            Edge &e = G[prv[v]][pre[v]];
            e.cap -= d;
            G[v][e.rev].cap += d;
        }
    }
    return res;
    //return f;
}

int n;
int getid1(int x, int y) { return x*n+y+1; }
int getid2(int x, int y) { return x*n+y+n*n+1; }
int a[30][30];
int main()
{
    while (~scanf("%d", &n)) {
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                scanf("%d", &a[i][j]);
            }
        }
        for (int i = 0; i <= 2*n*n; ++i) G[i].clear();
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                if (i+j == 0) addedge(getid1(i,j), getid2(i,j), 2, -a[i][j]);
                else if (i+j == n*2 - 2) addedge(getid1(i,j), getid2(i, j), 2, -a[i][j]);
                else addedge(getid1(i, j), getid2(i, j), 1, -a[i][j]);
                if (i+1<n) addedge(getid2(i, j), getid1(i+1, j), 1, 0);
                if (j+1<n) addedge(getid2(i, j), getid1(i, j+1), 1, 0);
            }
        }
        printf("%d\n", -min_cost_max_flow(getid1(0,0), getid2(n-1,n-1)) - a[0][0] - a[n-1][n-1]);
    }
    return 0;
}

hdu2686

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <bitset>
#include <cstdio>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <map>
#include <set>
#define pk(x) printf("%d\n", x)
using namespace std;
#define PI acos(-1.0)
#define EPS 1E-6
#define clr(x,c) memset(x,c,sizeof(x))
//#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;

const int MAXV = 610*610*2+2;
const int INF = 1<<30;

struct Edge { int to, cap, cost, rev; };
vector<Edge> G[MAXV];
int dist[MAXV], prv[MAXV], pre[MAXV], in[MAXV];
queue<int> que;

void addedge(int from, int to, int cap, int cost) {
    G[from].push_back((Edge){to, cap, cost, G[to].size()});
    G[to].push_back((Edge){from, 0, -cost, G[from].size()-1});
}

int min_cost_max_flow(int s, int t) { //, int f) {
    int res = 0;
    int f = 0;
    while (1) { //f > 0) {
        for (int i = 1; i <= t; ++i) dist[i] = INF, in[i] = 0;
        dist[s] = 0;
        while (!que.empty()) que.pop();
        in[s] = 1;
        que.push(s);

        while (!que.empty()) {
            int u = que.front(); que.pop(); in[u] = 0;
            for (int i = 0; i < G[u].size(); ++i) {
                Edge &e = G[u][i];
                if (e.cap > 0 && dist[e.to] > dist[u] + e.cost) {
                    dist[e.to] = dist[u] + e.cost;

                    prv[e.to] = u;
                    pre[e.to] = i;
                    if (in[e.to] == 0) {
                        in[e.to] = 1;
                        que.push(e.to);
                    }
                }
            }
        }

        if (dist[t] == INF) break; //return -1;

        int d = INF; // d = f;
        for (int v = t; v != s; v = prv[v]) {
            d = min(d, G[prv[v]][pre[v]].cap);
        }
        f += d;
        res += d * dist[t];
        for (int v = t; v != s; v = prv[v]) {
            Edge &e = G[prv[v]][pre[v]];
            e.cap -= d;
            G[v][e.rev].cap += d;
        }
    }
    return res;
    //return f;
}

inline int Scan()
{
    char ch = getchar();
    int data = 0;
    while (ch < ‘0‘ || ch > ‘9‘) ch = getchar();
    do {
        data = data*10 + ch-‘0‘;
        ch = getchar();
    } while (ch >= ‘0‘ && ch <= ‘9‘);
    return data;
}

int n;
int getid1(int x, int y) { return x*n+y+1; }
int getid2(int x, int y) { return x*n+y+n*n+1; }
int a[600][600];
int main()
{
    while (~scanf("%d", &n)) {
        int maxn = 2*n*n;
        for (int i = 0; i <= maxn; ++i) G[i].clear();
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                a[i][j] = Scan();
                if (i+j == 0 || i+j == n*2-2) addedge(getid1(i,j), getid2(i,j), 2, -a[i][j]);
                else addedge(getid1(i, j), getid2(i, j), 1, -a[i][j]);
                if (i+1<n) addedge(getid2(i, j), getid1(i+1, j), 1, 0);
                if (j+1<n) addedge(getid2(i, j), getid1(i, j+1), 1, 0);
            }
        }
        printf("%d\n", -min_cost_max_flow(getid1(0,0), getid2(n-1,n-1)) - a[0][0] - a[n-1][n-1]);
    }
    return 0;
}

hdu3376

时间: 2024-12-14 13:48:41

HDU2686-Matrix & HDU3376-Matrix Again(费用流)的相关文章

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

POJ 3422 Kaka&#39;s Matrix Travels(网络流之费用流)

题目地址:POJ 3422 方法是对每个点i拆点成i'和i'',然后对每个i'和i''连一条费用为该点值,流量为1的边,再连1条费用为0,流量为k-1的边. 然后对每个点与右边下边相邻的点连边,流量均为INF,费用均为0.需要再建一源点与汇点,对于k次只需要在源点与汇点处进行限制即可. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #inclu

hdu 3376 Matrix Again【最大费用流】

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

费用流 hdu3376 Matrix Again

传送门:点击打开链接 n太大了所以不能使用O(n^4)的dp来做了,只能考虑更复杂的费用流 主要的问题还是难在如何建图 将点拆分成两个,分别用i和i+n*n来表示 对于n*n个点,从i到i+n*n建一条边费用是-A[i][j]容量是1,来表示路过(i,j)获取的值 然后从第二层建两条边,连向右边和下边的两个点的第一层,让点再次回到第一层,费用是0 这样下来,点从第一层到第二层,表示获取了这个点的值,而且如果不获取这个值,就无法到达第二层,就无法继续扩展了. 所以就限制了每个点只能走一次了~ 最后

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

POJ 3422 kaka&#39;s matrix trvals(费用流)

#include <iostream> #include <cstring> #include <cstdio> #include <cstdlib> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <set> #include <map> #include <cma

POJ训练计划3422_Kaka&#39;s Matrix Travels(网络流/费用流)

解题报告 题目传送门 题意: 从n×n的矩阵的左上角走到右下角,每次只能向右和向下走,走到一个格子上加上格子的数,可以走k次.问最大的和是多少. 思路: 建图:每个格子掰成两个点,分别叫"出点","入点", 入点到出点间连一个容量1,费用为格子数的边,以及一个容量∞,费用0的边. 同时,一个格子的"出点"向它右.下的格子的"入点"连边,容量∞,费用0. 源点向(0,0)的入点连一个容量K的边,(N-1,N-1)的出点向汇点连一

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

UVa 12534 Binary Matrix 2 zkw费用流模版题

题目链接:点击打开链接 思路: 我们首先假设这个图都是全0的 用n个点代表行,m个点代表列 用源点向行连一个值x 表示每行1的个数,向列连一个y表示每列y个1 则若行i和列j之间流过一个流量就表示 (i,j) 点填了1 那么若原来图中(i,j)点为0 则花费就是1 若原图中(i,j)点是1,则花费是-1 如此枚举x跑个费用流就好了 ==居然把我多年的白书费用流坑掉了... zkw走起啊 #include <stdio.h> #include <string.h> #include