题目:

洛谷2469

分析:

把题目翻译成人话:给一个带边权的DAG,求一个路径覆盖方案使路径边权总和最小。从点\(i\)开始的路径需要额外加上\(A_i\)的权值。

回xian忆chang一xue下xi不带权DAG的最小路径覆盖用网络流是怎么做的:把点\(u\)拆成\(u\)和\(u'\)两个点,如果原图存在边\((u,v)\)就在网络中连边\((u,v')\),然后源点\(s\)向所有\(u\)连边,所有\(v\)向汇点\(t\)连边,所有边容量均为\(1\),跑最大流。原图中点数\(n\)减去最大流就是最小路径覆盖。

考虑这样做的原理:最小路径覆盖中每个点属于且仅属于一条路径。对于任意包含多于\(1\)个点的路径,有且只有一个点入度为\(0\),一个点出度为\(0\),其余所有点入度、出度皆为\(1\)。网络中若\((s,u)\)有流量说明\(u\)出度为\(1\)(\(s\)流到\(u\)后必然要流向某个点\(v'\)),若\((u',t)\)有流量说明\(u\)入度为\(1\)(必须有某个点流到\(u'\),\((u',t)\)才有流量)。那么最大流就是所有点入度之和,\(n\)减去入度之和就是入度为\(0\)的点数,即路径起点的数量,即路径数。如果边\((u,v')\)有流量说明原图中\((u,v)\)这条边在最小路径覆盖中。

那么给每条边加上权以后呢?自然能想到把原图中边\((u,v)\)的权作为网络中\((u,v')\)的费用然后跑费用流

然后你就gg了

费用流全名叫“最小费用最大流”,是在保证流量最大的情况下的最小费用。在这道题中,就相当于首先要保证路径的条数最少(即流量最大),然后再使费用最小。此时要感谢某神犇T兔z崽z子给我说的我自己想出来的方法……先打个广告

戳我进入兔崽子的博客

\(s\)向每个\(u'\)连边,这条边有流量说明\(u\)入度为\(0\)(因为\((u',t)\)容量为\(1\),\((s,u‘)\)有流量就说明肯定没有别的点会流到\(u'\))。这样无论如何路径覆盖最大流都是\(n\),就消除了路径条数的影响,求出最小费用即为答案。

这种方案顺便解决了下一个问题:路径起点有额外权值。把\(A_u\)作为\((s,u')\)的费用即可。

代码:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
namespace zyt
{
typedef long long ll;
const ll INF = 0x3f3f3f3f3f3f3f3fLL;
const int N = 810, P = N * 2, M = (N * 3 + 15010) * 2;
int head[P], cnt, n, m, s, t;
struct edge
{
int to, w, c, next;
}e[M];
inline void add(const int a, const int b, const int c, const int d)
{
e[cnt] = (edge){b, c, d, head[a]};
head[a] = cnt++;
}
inline void addtw(const int a, const int b, const int c, const int d)
{
add(a, b, c, d);
add(b, a, 0, -d);
}
namespace EK
{
bool vis[P];
ll dis[P];
int pre[P];
bool SPFA()
{
queue<int>q;
memset(pre, -1, sizeof(pre));
memset(vis, 0, sizeof(vis));
memset(dis, INF, sizeof(dis));
q.push(s);
vis[s] = true;
dis[s] = 0;
while (!q.empty())
{
int u = q.front();
q.pop();
vis[u] = false;
for (int i = head[u]; ~i; i = e[i].next)
{
int v = e[i].to;
if (e[i].w && dis[v] > dis[u] + e[i].c)
{
dis[v] = dis[u] + e[i].c, pre[v] = i;
if (!vis[v])
vis[v] = true, q.push(v);
}
}
}
return dis[t] != INF;
}
ll EK()
{
ll ans = 0;
while (SPFA())
{
int i = pre[t];
int minn = n + 1;
while (~i)
minn = min(minn, e[i].w), i = pre[e[i ^ 1].to];
i = pre[t];
while (~i)
e[i].w -= minn, e[i ^ 1].w += minn, i = pre[e[i ^ 1].to];
ans += minn * dis[t];
}
return ans;
}
}
int work()
{
ios::sync_with_stdio(false);
memset(head, -1, sizeof(head));
cin >> n >> m;
s = n * 2 + 1, t = n * 2 + 2;
for (int i = 1; i <= n; i++)
{
int a;
cin >> a;
addtw(s, i, 1, 0);
addtw(s, i + n, 1, a);
addtw(i + n, t, 1, 0);
}
for (int i = 0; i < m; i++)
{
int a, b, c;
cin >> a >> b >> c;
if (a > b)
swap(a, b);
addtw(a, b + n, 1, c);
}
cout << EK::EK();
return 0;
}
}
int main()
{
return zyt::work();
}

【洛谷2469/BZOJ1927】[SDOI2010]星际竞速(费用流/最小路径覆盖)的更多相关文章

  1. BZOJ 1927: [Sdoi2010]星际竞速 费用流

    1927: [Sdoi2010]星际竞速 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...

  2. Luogu2469 SDOI2010 星际竞速 费用流

    传送门 发现它的本质是求一个费用最小的路径覆盖 最小路径覆盖是网络流23题中的一个比较典型的模型 所以考虑相似的建边 因为每一个点要恰好经过一次,是一个有上下界的网络流,故拆点,星球\(i\)拆成\( ...

  3. BZOJ 1927: [Sdoi2010]星际竞速(费用流)

    传送门 解题思路 仿照最小路径覆盖问题,用费用流解决此题.最小路径覆盖问题是拆点连边后用\(n-\)最大匹配,这里的话也是将每个点拆点,源点向入点连流量为\(1\),费用为\(0\)的边,向出点连流量 ...

  4. [SDOI2010]星际竞速——费用流

    类似于最短路的网络流,而且还要保证每个点经过一次,拆点就比较方便了. 连边怎么连?要保证最大流是n(每个点经过一次)还要能从直接跳转 将每个点拆点.源点向每个点的入点连一条容量为1费用为0的边.源点向 ...

  5. BZOJ1927 [Sdoi2010]星际竞速 【费用流】

    1927: [Sdoi2010]星际竞速 Time Limit: 20 Sec  Memory Limit: 259 MB Submit: 2582  Solved: 1601 [Submit][St ...

  6. BZOJ1927: [Sdoi2010]星际竞速(最小费用最大流 最小路径覆盖)

    题意 题目链接 Sol 看完题不难想到最小路径覆盖,但是带权的咋做啊?qwqqq 首先冷静思考一下:最小路径覆盖 = \(n - \text{二分图最大匹配数}\) 为什么呢?首先最坏情况下是用\(n ...

  7. bzoj1927: [Sdoi2010]星际竞速

    跟上一题几乎一样... #include<cstdio> #include<cstring> #include<iostream> #include<algo ...

  8. BZOJ 1927 星际竞速(费用流)

    考虑费用流,题目要求走n个点都走完且恰好一次,显然流量的限制为n. 建立源点s和汇点t,并把每个星球拆成两个点i和i',分别表示已到达该点和经过该点. 对于能力爆发,建边(s,i',1,w). 对应高 ...

  9. 洛谷 P4016负载平衡问题【费用流】题解+AC代码

    洛谷 P4016负载平衡问题 P4014 分配问题[费用流]题解+AC代码 负载平衡问题 题目描述 GG 公司有n个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等.如何用最少搬运量可以使 n ...

随机推荐

  1. linux下的进程

    一.进程的基础: 1.程序:程序是一些保存在磁盘上的指令的有序集合: 2.进程:进程是程序的一次执行过程: 3.进程与程序的关系:①.程序是静态的,进程是动态的:  ②.一个程序可以对应多个进程:   ...

  2. 洛谷 4251 [SCOI2015]小凸玩矩阵

    [题解] 二分答案+二分图匹配. 先二分最小值Min,然后扫一遍这个矩阵,把满足a[i][j]<=Min的i,j连边,之后跑二分图匹配,如果最大匹配数大于等于n-k+1,当前的Min即是合法的. ...

  3. Codeforces 121A Lucky Sum

    Lucky Sum Time Limit: 2000ms Memory Limit: 262144KB This problem will be judged on CodeForces. Origi ...

  4. c++ 上机实验题

    c++语言俺是不会啦,但是朋友考试需要,那只能勉为其难的入门下做做考试题了. 以下就是具体的题目和答案: ----------------------------------------------- ...

  5. opengl 对投影变化函数的理解

    投影变化分两种: 1 . 平行投影       2 . 透视投影 投影变化的设置一般放在reshape函数当中调用 每次要对投影变化进行操作的时候我们需要修改矩阵的变化模式,指定它为投影变化 glMa ...

  6. [luoguP2387] 魔法森林(LCT + 并查集)

    传送门 并查集真是一个判断连通的好东西! 连通性用并查集来搞. 把每一条边按照 a 为关键字从小到大排序. 那么直接枚举,动态维护 b 的最小生成树 用 a[i] + 1 ~ n 路径上最大的 b[i ...

  7. noip模拟赛 洗衣

    分析:好神的一道题啊.对每棵树建个图跑一下floyd可以有40分,想要打出正解就得对树有比较深的认识了. 每次新生成一棵树都是由两棵树i,j拼成的,答案为原来两棵树的答案和+i中每个点到j中每个点的距 ...

  8. CentOS 安装Oracle 11g R2

    CentOS 安装Oracle 11g R2 学习了-/ https://www.osyunwei.com/archives/5445.html

  9. SQL Server死锁总结 [转]

    1. 死锁原理 根据操作系统中的定义:死锁是指在一组进程中的各个进程均占有不会释放的资源,但因互相申请被其他进程所站用不会释放的资源而处于的一种永久等待状态. 死锁的四个必要条件:互斥条件(Mutua ...

  10. Springmvc 一个简单的管理系统 我所遇到的坑1(持续更新)

    前言 好久没有用springmvc写项目了,抽时间写一个简单的springmvc项目 是什么(what)为什么(why)怎么做(how) 1.读书破万卷下笔如有神(理清思路,知识储备和前期整理) 2. ...