Luogu P4553 80人环游世界
题目大意
自东向西有 \(n\) 个国家。有 \(m\) 个人,他们可以选择 \(n\) 个国家中任意一个开始,任意一个结束,但路线必须自东向西,且第 \(i\) 个国家必须恰好经过 \(v_i\) 人。已知每个国家到它西方的国家的费用,求最小花费。
最小费用最大流
蒟蒻不会上下界,看了一些大佬写的费用流,想了一下,发表一下自己的理解,希望对大家有帮助。
首先因为对于每个点(国家)都有经过限制,所以将拆点为入点和出点。 \(i\rightarrow (i,i+n)\)
\(s\) 向第 \(i\) 入点连容量 \(v_i\) 费用 \(0\) 的边,因为每个国家必须要有 \(v_i\) 人来,连这条边就相当于这 \(v_i\) 个人进入了该国。
同理,出点向 \(t\) 连容量 \(v_i\)费用 \(0\) 的边,表示有 \(v_i\) 个人到达了这个国家。
对于每条航线 \((u,v)\),由 \(u\) 的入点向 \(v\) 的出点连容量 \(\infty\) 费用 \(0\) 的边,表示进入国家 \(u\) 的人可以前往国家 \(v\) 并声明到达了国家 \(v\) (即从 \(v\) 的出点到达汇点)。
最后额外再建一个点,由 \(s\) 向它连容量 \(m\) 费用 \(0\) 的边,然后让他向每个出点连容量 \(\infty\) 费用 \(0\) 的边表示这 \(m\) 个人可以随便选出发点。
然后跑最小费用最大流即可。
考虑正确性:因为跑的是最大流,所以每个出点到汇点的边一定会跑满,也就保证了每个国家限定经过次数。
又因为从那个额外点到其他出点的边费用为 \(0\) 所以这些边会被优先选择,也就意味着从源点到额外点着条边一定会跑满,也就意味着这 \(m\) 个人一定会出发(不会有人临阵脱逃)。
Code
#include<bits/stdc++.h>
//#define int long long
#define pair pair<int,int>
using namespace std;
inline void end()
{
puts("");
system("pause");
}
inline int read()
{
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
const int N=222,M=2e4+4,inf=0x3f3f3f3f,INF=1e9;
int s,t,maxf,minc;
int first[N],nex[M],to[M],w[M],c[M],num=1;
inline void add(int u,int v,int val,int cos)
{
nex[++num]=first[u];
first[u]=num;
to[num]=v;
w[num]=val;
c[num]=cos;
}
inline void Add(int u,int v,int val,int cos)
{
add(u,v,val,cos);
add(v,u,0,-cos);
}
int dis[N],vis[N],cur[N];
inline bool SPFA()
{
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
deque<int> q;
q.push_back(s);
vis[s]=1;dis[s]=0;
while(!q.empty())
{
int u=q.front();q.pop_front();vis[u]=0;
for(int i=first[u];i;i=nex[i])
{
int v=to[i];
if(!w[i]) continue;
if(dis[v]>dis[u]+c[i])
{
dis[v]=dis[u]+c[i];
if(!vis[v])
{
vis[v]=1;
if(q.empty()||dis[v]>dis[q.front()]) q.push_back(v);
else q.push_front(v);
}
}
}
}
if(dis[t]==inf) return 0;
return 1;
}
int dfs(int u,int in)
{
if(u==t) return in;
vis[u]=1;
int out=0;
for(int i=cur[u];i;i=nex[i])
{
int v=to[i];
if(!w[i]||vis[v]) continue;
if(dis[v]==dis[u]+c[i])
{
int res=dfs(v,min(w[i],in-out));
w[i]-=res;
w[i^1]+=res;
out+=res;
minc+=c[i]*res;
if(in==out) break;
}
}
vis[u]=0;
if(!out) vis[u]=1;
return out;
}
void Dinic()
{
while(SPFA())
{
memcpy(cur,first,sizeof(first));
while(1)
{
int detal=dfs(s,1e9);
if(!detal) break;
maxf+=detal;
}
}
}
int n,m,v[N],ex;
main()
{
n=read(),m=read();ex=2*n+1;s=0,t=ex+1;
//ex为额外点
Add(s,ex,m,0);
for(int i=1;i<=n;++i)
{
v[i]=read();
Add(i+n,t,v[i],0);
Add(ex,i+n,INF,0);
}
for(int i=1;i<=n;++i)
{
Add(s,i,v[i],0);
for(int j=i+1;j<=n;++j)
{
int val=read();
if(val==-1) continue;
Add(i,j+n,INF,val);
}
}
Dinic();//最小费用最大流
printf("%d",minc);
//end();
return 0;
}
Luogu P4553 80人环游世界的更多相关文章
- P4553 80人环游世界
题目地址:P4553 80人环游世界 上下界网络流 无源汇上下界可行流 给定 \(n\) 个点, \(m\) 条边的网络,求一个可行解,使得边 \((u,v)\) 的流量介于 \([B(u,v),C( ...
- P4553 80人环游世界(上下界费用流)
P4553 80人环游世界 emm......先从上下界网络流(转)开始 再到现在的上下界费用流 因为有上下界,我们需要记下每个点的流量差$ex[i]$,用于调整 $ins(x,y,l,r,v)=li ...
- 洛谷P4553 80人环游世界
题目描述 https://www.luogu.org/problemnew/show/P4553 题解 思路比较显然,把图建出来,一个国家拆成两个点,中间设置上下界,然后跑费用流. 我把源那边的流量也 ...
- 【BZOJ-2055】80人环游世界 上下界费用流 (无源无汇最小费用最大流)
2055: 80人环游世界 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 321 Solved: 201[Submit][Status][Discus ...
- BZOJ2055: 80人环游世界
题解: 总算A掉了,各种蛋疼... int main() { freopen("input.txt","r",stdin); freopen("out ...
- BZOJ 2055: 80人环游世界 [上下界费用流]
2055: 80人环游世界 题意:n个点带权图,选出m条路径,每个点经过val[i]次,求最小花费 建图比较简单 s拆点限制流量m 一个点拆成两个,限制流量val[i],需要用上下界 图中有边的连边, ...
- [BZOJ2055]80人环游世界 有上下界最小费用最大流
2055: 80人环游世界 Time Limit: 10 Sec Memory Limit: 64 MB Description 想必大家都看过成龙大哥的<80天环游世界>,里面 ...
- bzoj 2055: 80人环游世界 -- 上下界网络流
2055: 80人环游世界 Time Limit: 10 Sec Memory Limit: 64 MB Description 想必大家都看过成龙大哥的<80天环游世界>,里面 ...
- 【BZOJ】2055 80人环游世界
[算法]有源汇上下界最小费用可行流 [题解]上下界 因为上下界相同,所以无所谓最小流了,可行流(初始流+附加流)就是答案了. 记得源点向新建节点连一条容量为m(人)的边. bzoj 2055 80人环 ...
随机推荐
- python3操作Kafka
# -- coding: UTF-8 import datetime import json import time from kafka import KafkaProducer producer= ...
- Python+Selenium学习笔记17 - HTML测试报告
运行少量case时 1 # coding = utf-8 2 3 from selenium import webdriver 4 import unittest 5 import time 6 fr ...
- VAE变分自编码器实现
变分自编码器(VAE)组合了神经网络和贝叶斯推理这两种最好的方法,是最酷的神经网络,已经成为无监督学习的流行方法之一. 变分自编码器是一个扭曲的自编码器.同自编码器的传统编码器和解码器网络一起,具有附 ...
- Mobileye 自动驾驶策略(一)
Mobileye 自动驾驶策略(一) 详解 Mobileye 自动驾驶解决方案 Mobileye的自动驾驶解决方案.总得来说,分为四种: Visual perception and sensor fu ...
- JDBC连接MongoDB
pom文件中导入驱动 <!-- MongoDB驱动 --> <dependency> <groupId>org.mongodb</groupId> &l ...
- flume采集MongoDB数据到Kafka中
环境说明 centos7(运行于vbox虚拟机) flume1.9.0(自定义了flume连接mongodb的source插件) jdk1.8 kafka(2.11) zookeeper(3.57) ...
- 使用ElementTree解析,操作xml
一.最近在实际工作中需要对一部分接口进行测试,接口的入参与出参都是xml格式的数据,所以用到了python内部模块ElementTree对xml进行解析,并根据实际需求操作xml数据 二.代码示例 # ...
- 【NX二次开发】创建有界平面UF_MODL_create_bplane
先准备几条曲线如下图所示,我们用这几条线来创建一个有界平面: 效果: 源码: //有界平面 extern DllExport void ufusr(char *param, int *returnC ...
- Linkerd 2.10(Step by Step)—将 GitOps 与 Linkerd 和 Argo CD 结合使用
Linkerd 2.10 系列 快速上手 Linkerd v2.10 Service Mesh(服务网格) 腾讯云 K8S 集群实战 Service Mesh-Linkerd2 & Traef ...
- 用jquery通过点击事件把下拉列表币种的值传给文本框1,再通过文本框1的币种名称用if转化为币别传值给文本框2保存
<script src="https://cdn.staticfile.org/jquery/2.2.4/jquery.min.js"></script>& ...