[最短路,最大流最小割定理] 2019 Multi-University Training Contest 1 Path
题目:http://acm.hdu.edu.cn/showproblem.php?pid=6582
Path
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 3747 Accepted Submission(s): 1075
After doing some research on the neighbourhood, Tom found that the neighbourhood consists of exactly n houses, and some of them are connected with directed road. To visit his girlfriend, Jerry needs to start from his house indexed 1 and go along the shortest path to hers, indexed n.
Now Tom wants to block some of the roads so that Jerry has to walk longer to reach his girl's home, and he found that the cost of blocking a road equals to its length. Now he wants to know the minimum total cost to make Jerry walk longer.
Note, if Jerry can't reach his girl's house in the very beginning, the answer is obviously zero. And you don't need to guarantee that there still exists a way from Jerry's house to his girl's after blocking some edges.
Each test case starts with a line containing two numbers n,m(1≤n,m≤10000), the number of houses and the number of one-way roads in the neighbourhood.
m lines follow, each of which consists of three integers x,y,c(1≤x,y≤n,1≤c≤109), denoting that there exists a one-way road from the house indexed x to y of length c.
3 4
1 2 1
2 3 1
1 3 2
1 3 3
题意:
给n个节点m条有向边,现在可以删去一些边,代价为边权,问最小代价删去一些边使得现在节点1到节点n的最短路不成立(如果1不可达n则答案为0)
思路:
可能有多条1到n的最短路,这些最短路组成图,以最小代价使图不连通就是求最小割,由最大流最小割定理可知,最小割等于最大流,所以我们先找出图中1到n的最短路新建一个图,在这个图上从1到n跑一边最大流就可求出答案
现在就是建图的问题,我们先得到1到n的最短路径dis[i],再得到n到1的最短路径dis1[i],再把原图中符合dis[u]+e[i].w+dis1[v]==dis[n](令e[i].w为节点u到v的边权)的边建一个新图,
在这个新图上从1到n跑一边dinic就可得到答案
注意:
调了一个下午,在bool operator(const node &a)const{return a.w<w;}中原来是要a.w<w才能让优先队列中w小的优先,如果是a.w>w则是w大的优先
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int amn=1e4+;
const ll inf=1e18;
struct edge{
int from,to,nex;ll w;
}eg[amn],eg1[amn],e[amn<<|];
struct node{
int p;
ll w;
node(int pp,ll ww){p=pp;w=ww;}
bool operator<(const node &a)const{return a.w<w;} ///调了一个下午,原来是要a.w<w才行,这样优先队列中才会w小的优先,如果是a.w>w则是w大的优先
};
ll head[amn],egn,head1[amn],egn1,n,m,dis[amn],dis1[amn],vis[amn],head2[amn],egn2;
void init(int n){
egn=,egn1=,egn2=; ///egn2是跑最大流的,初始为1,这样就可以从2开始加边,这样正向边和反向边相邻储存,因为2^1=3,3^1=2...所以可以异或得到正向边反向边
for(int i=;i<=n;i++)head2[i]=head1[i]=head[i]=;
}
void add(int u,int v,ll w){ ///正向图加边
eg[++egn].nex=head[u];
head[u]=egn;
eg[egn].from=u;
eg[egn].to=v;
eg[egn].w=w;
}
void add1(int u,int v,ll w){ ///反向图加边
eg1[++egn1].nex=head1[u];
head1[u]=egn1;
eg1[egn1].from=u;
eg1[egn1].to=v;
eg1[egn1].w=w;
}
void add2(int u,int v,ll w){ ///跑最大流的新图加边
e[++egn2].nex=head2[u];
head2[u]=egn2;
e[egn2].from=u;
e[egn2].to=v;
e[egn2].w=w;
} ///以1为起点跑最短路
void dijkstra(int s){
memset(vis,,sizeof vis);
for(int i=;i<=n;i++)dis[i]=inf;
dis[s]=;
priority_queue<node> q;
q.push(node(s,dis[s]));
while(q.size()){
int u=q.top().p;
ll w=q.top().w;q.pop();
if(w>dis[u])continue;
vis[u]=;
for(int i=head[u];i;i=eg[i].nex){
int v=eg[i].to;
if(!vis[v]&&((dis[v])>(eg[i].w)+(dis[u]))){
dis[v]=(eg[i].w)+dis[u];
q.push(node(v,(dis[v])));
}
}
}
}
///以n为起点跑最短路
void dijkstra1(int s){
memset(vis,,sizeof vis);
for(int i=;i<=n;i++)dis1[i]=inf;
dis1[s]=;
priority_queue<node> q;
q.push(node(s,dis1[s]));
while(q.size()){
int u=q.top().p;
ll w=q.top().w;q.pop();
if(w>dis1[u])continue;
vis[u]=;
for(int i=head1[u];i;i=eg1[i].nex){
int v=eg1[i].to;
if(!vis[v]&&((dis1[v])>(eg1[i].w)+(dis1[u]))){
dis1[v]=(eg1[i].w)+dis1[u];
q.push(node(v,(dis1[v])));
}
}
}
}
///dinic最大流
queue<int> que;
ll dist[amn],src=,sink=n;
void bfs(){
memset(dist,,sizeof dist);
while(que.size())que.pop();
vis[src]=;
que.push(src);
while(que.size()){
int u=que.front();que.pop();
for(int i=head2[u];i;i=e[i].nex){
int v=e[i].to;//cout<<'>'<<e[i].w<<' '<<v<<endl;
if(e[i].w&&!vis[v]){
que.push(v);
dist[v]=dist[u]+;
vis[v]=;
}
}
}
}
int dfs(int u,ll delta){
if(u==sink)return delta;
int ret=;
for(int i=head2[u];delta&&i;i=e[i].nex)
if(e[i].w&&(dist[e[i].to]==dist[u]+)){
ll dd=dfs(e[i].to,min(e[i].w,delta));
e[i].w-=dd;
e[i^].w+=dd;
delta-=dd;
ret+=dd;
}
return ret;
}
ll maxflow(){
ll ret=;
while(){
memset(vis,,sizeof vis);
bfs();
if(!vis[sink])return ret;//cout<<'<'<<ret<<endl;
ret+=dfs(src,inf);
}
}
int main(){
int T,x,y;ll c;
scanf("%d",&T);
while(T--){
scanf("%lld%lld",&n,&m);
init(n); ///初始化
src=,sink=n; ///设置1为源点,n为汇点
for(int i=;i<=m;i++){
scanf("%d%d%lld",&x,&y,&c);
add(x,y,c); ///正向图,为了以1为起点跑最短路
add1(y,x,c); ///反向图,为了以n为起点跑最短路
}
dijkstra(); ///以1为起点的最短路
if(dis[n]==inf){printf("0\n");continue;} ///如果1到n不可达则输出0
dijkstra1(n); ///以n为起点的最短路
for(int i=;i<=egn;i++){
// cout<<eg[i].from<<' '<<eg[i].to<<' '<<eg[i].w<<endl;
// cout<<dis[eg[i].from]<<' '<<eg[i].w<<' '<<dis1[eg[i].to]<<' '<<dis[n]<<endl<<endl;
if(dis[eg[i].from]+eg[i].w+dis1[eg[i].to]==dis[n]){ ///如果1到现在这个点u的最短路径+u到v的边权+v到n的最短路径==1到n的最短路径则u到v这条边是最短路中的一条边
add2(eg[i].from,eg[i].to,eg[i].w); ///建新图,加正向边
add2(eg[i].to,eg[i].from,); ///边权为0的反向边
}
}
printf("%lld\n",maxflow()); ///最大流等于最小割
}
}
/**
给n个节点m条有向边,现在可以删去一些边,代价为边权,问最小代价删去一些边使得现在节点1到节点n的最短路不成立(如果1不可达n则答案为0)
可能有多条1到n的最短路,这些最短路组成图,以最小代价使图不连通就是求最小割,由最大流最小割定理可知,最小割等于最大流,所以我们先找出图中1到n的最短路新建一个图,在这个图上从1到n跑一边最大流就可求出答案
现在就是建图的问题,我们先得到1到n的最短路径dis[i],再得到n到1的最短路径dis1[i],再把原图中符合dis[u]+e[i].w+dis1[v]==dis[n](令e[i].w为节点u到v的边权)的边建一个新图,
在这个新图上从1到n跑一边dinic就可得到答案
调了一个下午,在bool operator(const node &a)const{return a.w<w;}中原来是要a.w<w才能让优先队列中w小的优先,如果是a.w>w则是w大的优先
**/
[最短路,最大流最小割定理] 2019 Multi-University Training Contest 1 Path的更多相关文章
- hiho 第116周,最大流最小割定理,求最小割集S,T
小Hi:在上一周的Hiho一下中我们初步讲解了网络流的概念以及常规解法,小Ho你还记得内容么? 小Ho:我记得!网络流就是给定了一张图G=(V,E),以及源点s和汇点t.每一条边e(u,v)具有容量c ...
- hihocoder 网络流二·最大流最小割定理
网络流二·最大流最小割定理 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi:在上一周的Hiho一下中我们初步讲解了网络流的概念以及常规解法,小Ho你还记得内容么? ...
- [HihoCoder1378]网络流二·最大流最小割定理
思路: 根据最大流最小割定理可得最大流与最小割相等,所以可以先跑一遍EdmondsKarp算法.接下来要求的是经过最小割切割后的图中$S$所属的点集.本来的思路是用并查集处理所有前向边构成的残量网络, ...
- 【codevs1907】方格取数3(最大流最小割定理)
网址:http://codevs.cn/problem/1907/ 题意:在一个矩阵里选不相邻的若干个数,使这些数的和最大. 我们可以把它看成一个最小割,答案就是矩阵中的所有数-最小割.先把矩阵按国际 ...
- 牛客暑期第六场G /// 树形DP 最大流最小割定理
题目大意: 输入t,t个测试用例 每个测试用例输入n 接下来n行 输入u,v,w,树的无向边u点到v点权重为w 求任意两点间的最大流的总和 1.最大流最小割定理 即最大流等于最小割 2.无向树上的任意 ...
- 2019 Multi-University Training Contest 1 Path(最短路+最小割)
题意:给你n个点 m条边 现在你能够堵住一些路 问怎样能让花费最少且让1~n走的路比最短路的长度要长 思路:先跑一边最短路 建一个最短路图 然后我们跑一边最大流求一下最小割即可 #include &l ...
- 2019HDU多校第一场 6582 Path 【最短路+最大流最小割】
一.题目 Path 二.分析 首先肯定要求最短路,然后如何确定所有的最短路其实有多种方法. 1 根据最短路,那么最短路上的边肯定是可以满足$dist[from] + e.cost = dist[to] ...
- 【hihocoder 1378】网络流二·最大流最小割定理
[Link]:http://hihocoder.com/problemset/problem/1378 [Description] [Solution] 在求完最小割(最大流)之后; 可以在剩余网络中 ...
- 2019 Nowcoder Multi-University Training Contest 4 E Explorer
线段树分治. 把size看成时间,相当于时间 $l$ 加入这条边,时间 $r+1$ 删除这条边. 注意把左右端点的关系. #include <bits/stdc++.h> ; int X[ ...
随机推荐
- 添砖加瓦:Linux /proc目录简介
Linux 内核提供了一种通过 /proc 文件系统,在运行时访问内核内部数据结构.改变内核设置的机制.proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间.它以文件系统的方式为访问系 ...
- 全平台Markdown笔记软件——Notable
简介 The markdown-based note-taking app that doesn't suck. 一款简介.跨平台的本地笔记软件,github地址:https://github.com ...
- 餐厅随评系列之四:Umu日本料理(米其林二星)
文章目录 在过去的几个月,工作和生活都极其忙碌,因此博客短暂停更了一阵子.慢慢积累下了很多素材,从近期开始恢复博客更新,不过很多内容估计得靠回忆了. 索性采取"倒叙"的方法,先从最 ...
- 从游戏到汽车 “明星IP”的发财轨迹
"明星IP"的发财轨迹" title="从游戏到汽车 "明星IP"的发财轨迹"> 移动互联网时代的开启,不仅彻底重构了大众生 ...
- Spring编译后没有xml配置文件解决方法
问题描述 在使用Maven来构建Spring项目的时候,使用下面代码来读取Spring配置文件. ClassPathXmlApplicationContext context = new ClassP ...
- 启动时查看配置文件application.yml
Spring Boot Application 事件和监听器 在多环境的情况下. 可能需要切换配置文件的一个对应的属性来切换环境 面临的问题就是 如何在springboot加载完配置文件的时候就可以立 ...
- C#开发BIMFACE系列30 服务端API之模型对比1:发起模型对比
系列目录 [已更新最新开发文章,点击查看详细] 在实际项目中,由于需求变更经常需要对模型文件进行修改.为了便于用户了解模型在修改前后发生的变化,BIMFACE提供了模型在线对比功能,可以利用在 ...
- 先导篇:SpringCloud介绍篇
1.什么是SpringCloud Spring Cloud是一系列框架的有序集合.它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册.配置中心.消息总线.负载 ...
- js 面向对象中,定义一个函数的过程
定义一个函数做的两件事:1: 实例化一个Function对象:2: 实例化一个Object对象,并给该函数扩展prototype属性指向这个构造函数 大致过程如图所示: 每一种引用类型(函数,对象,数 ...
- Python基础-检测密码,一些网站会给密码强加一些规则。
输入一个字符串,检测是否是合法的密码:1)密码必须包含8个字符2)密码只能包含英文字母和数字3)密码至少包含两个数字 首先我讲一下用到的方法 s为字符串 len(s) 求出字符串的长度. list(s ...