ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

洛谷P1004 方格取数

2019-02-13 13:47:54  阅读:232  来源: 互联网

标签:洛谷 int P1004 取数 vis cost maxn 方格 dis


网络流大法吼

不想用DP的我选择了用网络流……

建模方法:

从源点向(1,1)连一条容量为2(走两次),费用为0的边

从(n,n)向汇点连一条容量为2,费用为0的边

每个方格向右边和下边的方格连一条容量为inf,费用为0的边

走到每个方格,会取出方格上的数。每个方格的数只会被取走一次。

于是我们考虑拆点

每个方格向拆出的点连一条容量为1(只能被取走一次),费用为方格上的数的边

由于每个方格不一定只走一次,所以再连一条容量为inf,费用为0的边

然后跑最大费用最大流就行了~


我的代码中把边上的费用取相反数,跑最小费用最大流,最后得出的最小费用取负就是答案啦~!

下面是代码:

#include <bits/stdc++.h>

using namespace std;

const int maxn = 210;

struct edge {
    int flow, cap, cost, t, next;
}e[maxn * 50];
int n, m, s, t, p = -1, head[maxn], maxflow, mincost = 0, pre[maxn], dis[maxn], a[maxn][maxn];
bool vis[maxn];

void add_edge(int s, int t, int cap, int cost) {
    p++;
    e[p].t = t;
    e[p].cap = cap;
    e[p].cost = cost;
    e[p].next = head[s];
    head[s] = p;
}

bool spfa() {
    queue < int > q;
    while(!q.empty())q.pop();
    memset(vis, 0, sizeof(vis));
    vis[s] = 1;
    q.push(s);
    memset(dis, 0x7f, sizeof(dis));
    memset(pre, -1, sizeof(pre));
    dis[s] = 0;
    while(!q.empty()) {
        int k = q.front();
        q.pop();
        vis[k] = false;
        for(int i = head[k]; i != -1; i = e[i].next) {
            if(e[i].cap && dis[e[i].t] > dis[k] + e[i].cost) {
                dis[e[i].t] = dis[k] + e[i].cost;
                pre[e[i].t] = i;
                if(!vis[e[i].t]) {
                    vis[e[i].t] = true;
                    q.push(e[i].t);
                }
            }
        }
    }
    // for(int i = 0; i <= n * n; i++) cout << dis[i] << " ";
    // cout << dis[t] << endl;
    if(dis[t] == 0x7f7f7f7f) return false;
    else return true;
}

void MCMF() {
    while(spfa()) {
        int mf = 0x7fffffff;
        for(int i = pre[t]; i != -1; i = pre[e[i ^ 1].t]) {
            mf = min(mf, e[i].cap);
            // cout << i << " " << pre[e[i ^ 1].t] << endl;
            // cout << e[2].cap << endl;
        }
        maxflow += mf;
        for(int i = pre[t]; i != -1; i = pre[e[i ^ 1].t]) {
            e[i].cap -= mf;
            e[i ^ 1].cap += mf;
        }
        mincost += mf * dis[t];
    }
}

int pos(int x, int y) {
    return (x - 1) * n + y;
}

int main() {
    memset(head, -1, sizeof(head));
    cin >> n;
    s = 0, t = maxn - 3;
    int x, y, z;
    while(1) {
        cin >> x >> y >> z;
        if(!(x || y || z)) break;
        a[x][y] = z;
    }
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= n; j++) {
            add_edge(pos(i, j), pos(i, j) + n * n, 1, -a[i][j]);
            add_edge(pos(i, j) + n * n, pos(i, j), 0, a[i][j]);
            add_edge(pos(i, j), pos(i, j) + n * n, 0x7fffffff, 0);
            add_edge(pos(i, j) + n * n, pos(i, j), 0, 0);
            if(i < n) {
                add_edge(pos(i, j) + n * n, pos(i + 1, j), 0x7fffffff, 0);
                add_edge(pos(i + 1, j), pos(i, j) + n * n, 0, 0);
            }
            if(j < n) {
                add_edge(pos(i, j) + n * n, pos(i, j + 1), 0x7fffffff, 0);
                add_edge(pos(i, j + 1), pos(i, j) + n * n, 0, 0);
            }
        }
    }
    add_edge(s, pos(1, 1), 2, 0);
    add_edge(pos(1, 1), s, 0, 0);
    add_edge(pos(n, n) + n * n, t, 2, 0);
    add_edge(t, pos(n, n) + n * n, 0, 0);
    MCMF();
    cout << -mincost << endl;
    return 0;
}

qwq

标签:洛谷,int,P1004,取数,vis,cost,maxn,方格,dis
来源: https://www.cnblogs.com/iycc/p/10369420.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有