首页 > 其他分享 >P4012 题解

P4012 题解

时间:2023-01-17 23:35:57浏览次数:71  
标签:icost cur int 题解 cost P4012 inque dis

前言

题目传送门!

更好的阅读体验?

网络流 \(24\) 题:最大费用最大流。

思路

首先我们只看每一个点。是典型的方格取数问题,可以考虑费用流。

对于一个相邻的、可以走到的点 \((x, y)\) 与 \((dx, dy)\),我们可以直接连边 \((x,y) \xrightarrow{cap=1\ cost=w} (dx,dy)\),表示:你想拿到这个格子的价值,那么你只能拿一次。

但是这样并不对。因为只是这样子,代表这一条边只能走一次。很显然这是不对的,因为你可以走这条边,但是什么都不拿。

于是我们再建一条 \((x,y) \xrightarrow{cap=\infty \ cost=0} (dx,dy)\),表示:这条边随便走,但是没有费用。

这就是第一步。我们再看一下源点与汇点:那 \(a\) 个点就是源点,那 \(b\) 个点就是汇点。

很套路地,建立多源多汇即可:超级源点连向每一个源点,超级汇点连向每一个汇点。

总结:

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
/**********最大费用最大流板子,可以换成自己的写法**********/
const int N = 1005, inf = 0x3f3f3f3f;
struct Edge {int now, nxt, w, cost;} e[114514];
int head[N], cur = 1;
void ad(int u, int v, int  w, int cost)
{
    e[++cur].now = v, e[cur].nxt = head[u], e[cur].w = w, e[cur].cost = cost;
    head[u] = cur;
}
void add(int u, int v, int w, int cost) {ad(u, v, w, cost), ad(v, u, 0, -cost);}
int dis[N], icost[N], pre[N]; bool inque[N];
int s, t;
bool spfa()
{
    queue <int> q;
    memset(dis, -0x3f, sizeof dis), memset(icost, 0, sizeof icost);
    q.push(s), dis[s] = 0, icost[s] = inf, inque[s] = true;
    while (!q.empty())
    {
        int u = q.front();
        q.pop(), inque[u] = false;
        for (int i = head[u]; i; i = e[i].nxt)
        {
            int v = e[i].now;
            if (!e[i].w) continue;
            if (dis[u] + e[i].cost > dis[v])
            {
                dis[v] = dis[u] + e[i].cost, pre[v] = i;
                icost[v] = min(icost[u], e[i].w);
                if (!inque[v]) q.push(v), inque[v] = true;
            }
        }
    }
    return icost[t] > 0;
}
int EK()
{
    int ans = 0;
    while (spfa())
    {
        int w = icost[t];
        ans += w * dis[t];
        for (int i = t; i != s; i = e[pre[i] ^ 1].now)
            e[pre[i]].w -= w, e[pre[i] ^ 1].w += w;
    }
    return ans;
}
/**********最大费用最大流板子,可以换成自己的写法**********/
int id[20][20];
int main()
{
    int a, b, n, m, idx = 0;
    scanf("%d%d%d%d", &a, &b, &n, &m);
    s = ++idx, t = ++idx;
    for (int i = 0; i <= n; i++)
        for (int j = 0; j <= m; j++)
            id[i][j] = ++idx; //给每个点一个编号
    for (int i = 0; i <= n; i++)
        for (int j = 0; j < m; j++)
        {
            int w;
            scanf("%d", &w);
            add(id[i][j], id[i][j + 1], 1, w), add(id[i][j], id[i][j + 1], inf, 0); //向可以走的点连边
        }
    for (int j = 0; j <= m; j++)
        for (int i = 0; i < n; i++)
        {
            int w;
            scanf("%d", &w);
            add(id[i][j], id[i + 1][j], 1, w), add(id[i][j], id[i + 1][j], inf, 0); //向可以走的点连边
        }
    while (a--)
    {
        int w, i, j;
        scanf("%d%d%d", &w, &i, &j);
        add(s, id[i][j], w, 0); //超级源点连边
    }
    while (b--)
    {
        int w, i, j;
        scanf("%d%d%d", &w, &i, &j);
        add(id[i][j], t, w, 0); //超级汇点连边
    }
    cout << EK();
    return 0;
}

希望能帮助到大家!

标签:icost,cur,int,题解,cost,P4012,inque,dis
From: https://www.cnblogs.com/liangbowen/p/17058926.html

相关文章

  • P3549 [POI2013]MUL-Multidrink 题解--zhengjun
    其他题解都是大码量的直接构造,来一发dp的题解。思路很明确,直接dp,然后输出路径即可。考虑先把\(1\ton\)的路径找出来,记为\(a_i(1\lei\lem)\)。那么肯定存在一种......
  • 【题解】P4482 [BJWC2018]Border 的四种求法
    思路SAM+树剖。好仙的题啊,做了一天。令\(\operatorname{lcs}(i,j)\)表示长度为\(i,j\)的前缀的最长公共后缀长度,则题目中的border可以等价转化成:求最大且满足......
  • Atcoder ABC 285 题解
    E-WorkorRest题意​ 一周有\(n\)天,给出一个长度为\(n\)的数组\(A\)。你可以决定一周中的休息日与工作日的分布,请问如何选择能够使总贡献最大。​ 如何计算贡献......
  • 【题解】P4768 [NOI2018] 归程(树上倍增,Kruskal 重构树,dijkstra)
    【题解】P4768[NOI2018]归程作为一道NOI的D1T1,放在现在或许难度不够(?),但可能在Kruskal重构树还未普及的当时,还是相对来说比较难的一道题吧。写篇题解记录一下。题......
  • P5020 [NOIP2018 提高组] 货币系统 题解
    注意:此题题解写的较为简略。P5020[NOIP2018提高组]货币系统转化为完全背包即可。#include<iostream>#include<cstring>#include<algorithm>usingnamespaces......
  • P1941 [NOIP2014 提高组] 飞扬的小鸟 题解
    WC-2023上的题目。线性动态规划P1941[NOIP2014提高组]飞扬的小鸟我们先不管障碍物。设\(f[i][j]\)表示来到点\((i,j)\)的最少点击屏幕数。因为每秒要不上升\(......
  • P1880 [NOI1995] 石子合并 题解
    P1880[NOI1995]石子合并区间DP。首先将其复制一遍(因为是环)。设\(f[i][j]\)表示将\(i\)到\(j\)段的石子合并需要的次数。有\[f[i][j]=0(i=j)\]\[f[i][j]......
  • 涂满它!(涂色问题 (原题:水叮当的舞步))题解
    F.涂满它!内存限制:256MiB时间限制:1000ms标准输入输出题目类型:传统评测方式:文本比较题目描述Flood-it是谷歌+平台上的非常好玩的一款游戏,游戏界面如下所示:在......
  • 2023牛客寒假算法基础集训营1题解
    写在前面全文收集了部分学长以及我自己的代码,本蒟蒻第一次写博客,效果不好请见谅TwT原题链接:https://ac.nowcoder.com/acm/contest/46800#questionA:WorldFinal?WorldC......
  • 洛谷普及组模拟赛 题解报告
    洛谷普及组模拟赛题解报告\[\bf{Prepared\by\InoueTakina.}\]前言:祝大家身体健康。本场比赛较为良心,经过了多次难度平衡,应该严格低于NOIP2018提高组,相信大家......