2019 Multi-University Training Contest 1 E Path(最短路+最小割)
题意
链接:https://vjudge.net/problem/HDU-6582
给定一个有向图,可以有重边,每条边上有一个权值表示删掉这条边的代价,问最少花费多少代价能使从s到t节点的最短路径增大?1≤n,m≤10000
思路
容易想到应该是删最短路上的边,最短路可能不止一条,所以使原图1到n的所有最短路不连通即可,这就是最小割呀!选出权值和最小的边使得图不连通,这里是使最短路图不连通。
所以做法就是先建两个图,一个是u->v的有向边,另一个是v->u的有向边,从1跑一下Dijkstra,从n跑一下Dijkstra,我们枚举每条边(u,v),如果这条边是最短路上的边,那么应满足dis1[u]+val(u,v)+dis2[v]=dis1[n],即1到u的最短距离+u到v的距离+v到n的最短距离=1到n的最短距离。
最小割=最大流,跑一下Dinic即可啦。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int ll
const int N=1e6+5;
const ll inf=1e16;
struct node
{
int p,w;
node(int a,int b)
{
p=a;
w=b;
}
friend bool operator<(node a,node b) //权值小的先出队
{
if(a.w!=b.w) return a.w>b.w;
return a.p>b.p;
}
};
vector <node> eg1[N],eg2[N];
int dis1[N],n,dis2[N];
void add1(int u,int v,int w)
{
eg1[u].push_back(node(v,w));
}
void add2(int u,int v,int w)
{
eg2[u].push_back(node(v,w));
}
void Dijkstra1(int now)
{
for(int i=0; i<=n; i++) dis1[i]=inf;
dis1[now]=0;
priority_queue <node> pq;
pq.push(node(now,dis1[now]));
while(!pq.empty())
{
node f=pq.top();
pq.pop();
for(int i=0; i<eg1[f.p].size(); i++)
{
node t=eg1[f.p][i];
if(dis1[t.p]>t.w+f.w)
{
dis1[t.p]=t.w+f.w;
pq.push(node(t.p,dis1[t.p]));
}
}
}
}
void Dijkstra2(int now)
{
for(int i=0; i<=n; i++) dis2[i]=inf;
dis2[now]=0;
priority_queue <node> pq;
pq.push(node(now,dis2[now]));
while(!pq.empty())
{
node f=pq.top();
pq.pop();
for(int i=0; i<eg2[f.p].size(); i++)
{
node t=eg2[f.p][i];
if(dis2[t.p]>t.w+f.w)
{
dis2[t.p]=t.w+f.w;
pq.push(node(t.p,dis2[t.p]));
}
}
}
}
/***************************************/
int x,y,z,maxflow,deep[N];//deep深度
struct Edge
{
int next,to,dis;
} edge[N];
int num_edge=-1,head[N],cur[N];//cur用于复制head
queue <int> q;
void add_edge(int from,int to,int dis,bool flag)
{
edge[++num_edge].next=head[from];
edge[num_edge].to=to;
if (flag) edge[num_edge].dis=dis;//反图的边权为 0
head[from]=num_edge;
}
//bfs用来分层
bool bfs(int s,int t)
{
memset(deep,0x7f,sizeof(deep));
while (!q.empty()) q.pop();
for (int i=1; i<=n; i++) cur[i]=head[i];
deep[s]=0;
q.push(s);
while (!q.empty())
{
int now=q.front();
q.pop();
for (int i=head[now]; i!=-1; i=edge[i].next)
{
if (deep[edge[i].to]>inf && edge[i].dis)//dis在此处用来做标记 是正图还是返图
{
deep[edge[i].to]=deep[now]+1;
q.push(edge[i].to);
}
}
}
if (deep[t]<inf) return true;
else return false;
}
//dfs找增加的流的量
int dfs(int now,int t,int limit)//limit为源点到这个点的路径上的最小边权
{
if (!limit || now==t) return limit;
int flow=0,f;
for (int i=cur[now]; i!=-1; i=edge[i].next)
{
cur[now]=i;
if (deep[edge[i].to]==deep[now]+1 && (f=dfs(edge[i].to,t,min(limit,edge[i].dis))))
{
flow+=f;
limit-=f;
edge[i].dis-=f;
edge[i^1].dis+=f;
if (!limit) break;
}
}
return flow;
}
void Dinic(int s,int t)
{
while (bfs(s,t))
maxflow+=dfs(s,t,inf);
}
/***********************************************/
signed main()
{
int u,v,m,w,t;
scanf("%lld",&t);
while(t--)
{
scanf("%lld%lld",&n,&m);
for(int i=0; i<=n; i++) eg1[i].clear(),eg2[i].clear();
for(int i=0; i<m; i++)
{
scanf("%lld%lld%lld",&u,&v,&w);
add1(u,v,w);
add2(v,u,w);
}
Dijkstra1(1);
Dijkstra2(n);
memset(head,-1,sizeof(head));
for(int i=1; i<=n; i++)
{
int sz=eg1[i].size();
for(int j=0; j<sz; j++)
{
if(dis1[i]+eg1[i][j].w+dis2[eg1[i][j].p]==dis1[n])
{
add_edge(i,eg1[i][j].p,eg1[i][j].w,1);
add_edge(eg1[i][j].p,i,eg1[i][j].w,0);
}
}
}
maxflow=0;
Dinic(1,n);
printf("%lld\n",maxflow);
}
return 0;
}
2019 Multi-University Training Contest 1 E Path(最短路+最小割)的更多相关文章
- 2019 Multi-University Training Contest 1 Path(最短路+最小割)
题意:给你n个点 m条边 现在你能够堵住一些路 问怎样能让花费最少且让1~n走的路比最短路的长度要长 思路:先跑一边最短路 建一个最短路图 然后我们跑一边最大流求一下最小割即可 #include &l ...
- [2019杭电多校第一场][hdu6582]Path(最短路&&最小割)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6582 题意:删掉边使得1到n的最短路改变,删掉边的代价为该边的边权.求最小代价. 比赛时一片浆糊,赛后 ...
- 2019HDU多校Path——最短路最小割
题目 给出一个 $n$ 个顶点 $m$ 条边的图,要求阻塞一些边,使得从 $1$ 到 $n$ 的最短路变长,求阻塞的边长度和的最小值,不必保证阻塞后可达. 分析 很显然,要阻塞的边肯定在最短路图上,先 ...
- HDU - 6582 Path (最短路+最小割)
题意:给定一个n个点m条边的有向图,每条边有个长度,可以花费等同于其长度的代价将其破坏掉,求最小的花费使得从1到n的最短路变长. 解法:先用dijkstra求出以1为源点的最短路,并建立最短路图(只保 ...
- 2019 Nowcoder Multi-University Training Contest 4 E Explorer
线段树分治. 把size看成时间,相当于时间 $l$ 加入这条边,时间 $r+1$ 删除这条边. 注意把左右端点的关系. #include <bits/stdc++.h> ; int X[ ...
- 2019 Nowcoder Multi-University Training Contest 1 H-XOR
由于每个元素贡献是线性的,那么等价于求每个元素出现在多少个异或和为$0$的子集内.因为是任意元素可以去异或,那么自然想到线性基.先对整个集合A求一遍线性基,设为$R$,假设$R$中元素个数为$r$,那 ...
- [2019杭电多校第二场][hdu6598]Harmonious Army(最小割)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6598 题意是说一个军队有n人,你可以给他们每个人安排战士或者法师的职业,有m对人有组合技,组合技的信息 ...
- [最短路,最大流最小割定理] 2019 Multi-University Training Contest 1 Path
题目:http://acm.hdu.edu.cn/showproblem.php?pid=6582 Path Time Limit: 2000/1000 MS (Java/Others) Mem ...
- 2019 Multi-University Training Contest 1
2019 Multi-University Training Contest 1 A. Blank upsolved by F0_0H 题意 给序列染色,使得 \([l_i,r_i]\) 区间内恰出现 ...
随机推荐
- mysql-python 安装错误: Cannot open include file: 'config-win.h': No such file or directory
问题描述: pip instal MySQL-python 出现如下错误: Installing collected packages: MySql-python Running setup.py i ...
- 单选框radio改变事件
<input type="radio" name="bedStatus" id="allot" checked="check ...
- MySQL 优化 (四)
参数优化 innodb_log_buffer_size 此参数确定些日志文件所用的内存大小,以M为单位.缓冲区更大能提高性能,对于较大的事务,可以增大缓存大小. innodb_log_buffer_s ...
- codeforces 1260C. Infinite Fence (数学or裴蜀定理)
只需要验证小间隔在大间隔之间有没有连续的k个 设小间隔为a,大间隔为b,那么a在b之间出现的次数在\(\lfloor \frac{b}{a}\rfloor\)或者\(\lfloor \frac{b}{ ...
- P3525 INS-Inspection
这道题的题面有点问题,如果按照题面做,应该是A不了的,下面引用一下评论里@REM_001的翻译 一棵n个节点的树,行动中心S从1->N.从S出发前往任意一个未标记到的点(沿树上两点的唯一路径走) ...
- 数据结构与算法-Python/C(目录)
第一篇 基本概念 01 什么是数据结构 02 什么是算法 03 应用实例-最大子列和问题 第二篇 线性结构 01 线性表及其实现 02 堆栈 03 队列 04 应用实例-多项式加法运算 05 小白专场 ...
- vb.net 带有一个参数的线程
For Each _row As DataGridViewRow In datagridview.Rows 'searchRecords_refreshRow(_row) ' 上面以前,直接运行函数, ...
- 【Linux命令】ldconfig动态链接库管理命令
ldconfig动态链接库管理命令,其目的为了让动态链接库为系统所共享. 作用: 默认搜寻/lilb和/usr/lib,以及配置文件/etc/ld.so.conf内所列的目录下的库文件. 搜索出可共享 ...
- 给HttpClient添加请求头(HttpClientFactory)
前言 在微服务的大环境下,会出现这个服务调用这个接口,那个接口的情况.假设出了问题,需要排查的时候,我们要怎么关联不同服务之间的调用情况呢?换句话就是说,这个请求的结果不对,看看是那里出了问题. 最简 ...
- 【LOJ#6682】梦中的数论(min_25筛)
[LOJ#6682]梦中的数论(min_25筛) 题面 LOJ 题解 注意题意是\(j|i\)并且\((j+k)|i\), 不难发现\(j\)和\((j+k)\)可以任意取\(i\)的任意因数,且\( ...