传送门

•题意

有n个城市,标号1-n

现花费最小的代价堵路

使得从1号城市到n号城市的路径边长

(注意只是变长不是最长)

堵一条路的代价是这条路的权值

•思路

在堵路以前,从1到n的最小路径当然是最短路

想要路径边长就要在最短路上动手脚

把从1到n的最短路找出来形成一个最短路图,

然后用最小的代价使得最短路图不连通

也就是求这个最短路图的最小割

那怎么建这个最短路图呢?

分别以1和n为源点跑一遍dijkstra,找出每个点到1和n的最短路

设$dis[1][i]$为1到i的最短路,$dis[n][i]$为i到n的最短路

$1->u->v->n$是$1->n$的一条最短路即$dis[1][u]+w[u->v]+dis[n][v]=dis[1][n]$

那么,u->v是1->n最短路上的一条边,加入最短路图中

(由于代码被某人嫌弃太乱,所以对dijkstra和dinic封装了一下...)

•代码

(未封装版)

 #include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
#define INF 0x3f3f3f3f3f3f3f3f
#define P pair<long long,int>
const int maxn=1e5+;
int n,m;
struct Edge
{
int v;
ll w;
int next;
}de[maxn],fe[maxn],e[maxn]; int head1[maxn],head2[maxn];
int cnt1,cnt2;
void add(int u,int v,ll w)
{
de[++cnt1]={v,w,head1[u]};
head1[u]=cnt1; fe[++cnt2]={u,w,head2[v]};
head2[v]=cnt2;
} ll dis1[maxn],disn[maxn];
bool vis1[maxn],visn[maxn];
priority_queue<P,vector<P>,greater<P> >pq; void dijkstra()
{
while(!pq.empty())
pq.pop();
for(int i=;i<=n;i++)
dis1[i]=INF,vis1[i]=;
dis1[]=;
pq.push(make_pair(,));
while(!pq.empty())
{
int u=pq.top().second;
pq.pop();
if(!vis1[u])
{
vis1[u]=;
for(int i=head1[u];~i;i=de[i].next)
{
int v=de[i].v;
dis1[v]=min(dis1[v],dis1[u]+de[i].w);
pq.push(make_pair(dis1[v],v));
}
}
} while(!pq.empty())
pq.pop();
for(int i=;i<=n;i++)
disn[i]=INF,visn[i]=;
disn[n]=; pq.push(make_pair(,n));
while(!pq.empty())
{
int u=pq.top().second;
pq.pop();
if(!visn[u])
{
visn[u]=;
for(int i=head2[u];~i;i=fe[i].next)
{
int v=fe[i].v;
disn[v]=min(disn[v],disn[u]+fe[i].w);
pq.push(make_pair(disn[v],v));
}
}
}
} int head[maxn],cnt;
int cur[maxn],d[maxn];
void addEdge(int u,int v,ll w)
{
e[++cnt]={v,w,head[u]};
head[u]=cnt; e[++cnt]={u,,head[v]};
head[v]=cnt;
} bool bfs()
{
queue<int> q;
for(int i=;i<=n;i++)
d[i]=-;
d[]=;
q.push();
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];~i;i=e[i].next)
{
int v=e[i].v;
if(d[v]==-&&e[i].w>)
{
d[v]=d[u]+;
q.push(v);
}
}
}
return d[n]!=-;
} ll dfs(int u,ll flow)
{
ll nowflow=;
if(u==n) return flow;
for(int i=cur[u];~i;i=e[i].next)
{
cur[u]=i;
int v=e[i].v;
if(d[v]==d[u]+&&e[i].w>)
{
ll k=dfs(v,min(flow-nowflow,e[i].w));
if(k)
{
nowflow+=k;
e[i].w-=k;
e[i^].w+=k;
if(nowflow==flow)
break;
}
}
}
if(!nowflow) d[u]=-;
return nowflow;
} ll Dinic()
{
ll ans=;
while(bfs())
{
for(int i=;i<=n;i++)
cur[i]=head[i]; ans+=dfs(,INF);
}
return ans;
} void Init()
{
mem(head1,-);
mem(head2,-);
mem(head,-);
cnt1=cnt2=cnt=-;
} int main()
{
// freopen("C:\\Users\\14685\\Desktop\\C++workspace\\in&out\\contest","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
Init();
for(int i=;i<=m;i++)
{
int u,v;
ll w;
scanf("%d%d%lld",&u,&v,&w);
add(u,v,w);
} dijkstra(); for(int u=;u<=n;u++)
{
for(int i=head1[u];~i;i=de[i].next)
{
int v=de[i].v;
if(dis1[u]+disn[v]+de[i].w==dis1[n])
{
// printf("***%d %d %d\n",u,v,de[i].w);
addEdge(u,v,de[i].w);
}
}
} printf("%lld\n",Dinic());
}
}

(封装版)

 #include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pli pair<ll,int>
#define INF 0x3f3f3f3f3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn=1e5+;
int n,m;
struct Edge
{
int v;
ll w;
int next;
}G[maxn<<],e[maxn<<];
int dhead[maxn],dcnt;
void addEdge(int u,int v,ll w)
{
G[++dcnt]={v,w,dhead[u]};
dhead[u]=dcnt;
} struct Dij
{
ll dis[][maxn];
bool vis[maxn];
priority_queue<pli,vector<pli>,greater<pli> > q;
void dij(int s,int n,bool ok)
{
for(int i=;i<=n;i++)
dis[ok][i]=INF,vis[i]=;
dis[ok][s]=;
q.push({,s});
while(!q.empty())
{
int u=q.top().second;
q.pop();
if(vis[u])
continue;
vis[u]=;
for(int i=dhead[u];~i;i=G[i].next)
{
///偶数是正向边,ok=true是正向边
if(ok && i&)
continue;
///奇数是反向边,ok=false是反向边
if(!ok && !(i&))
continue; int v=G[i].v;
ll w=G[i].w;
if(dis[ok][v]>dis[ok][u]+w)
{
dis[ok][v]=dis[ok][u]+w;
if(!vis[v])
q.push({dis[ok][v],v});
}
}
}
}
}dij; int head[maxn],cnt;
void add(int u,int v,ll w)
{
e[++cnt]={v,w,head[u]};
head[u]=cnt;
}
struct Dinic
{
int cur[maxn],d[maxn];
int s=,t=n;
bool bfs()
{
queue<int> q;
for(int i=;i<=n;i++)
d[i]=-;
d[]=;
q.push();
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];~i;i=e[i].next)
{
int v=e[i].v;
if(d[v]==-&&e[i].w>)
{
d[v]=d[u]+;
q.push(v);
}
}
}
return d[n]!=-;
} ll dfs(int u,ll flow)
{
ll nowflow=;
if(u==n) return flow;
for(int i=cur[u];~i;i=e[i].next)
{
cur[u]=i;
int v=e[i].v;
if(d[v]==d[u]+&&e[i].w>)
{
ll k=dfs(v,min(flow-nowflow,e[i].w));
if(k)
{
nowflow+=k;
e[i].w-=k;
e[i^].w+=k;
if(nowflow==flow)
break;
}
}
}
if(!nowflow) d[u]=-;
return nowflow;
} ll din()
{
ll ans=;
while(bfs())
{
for(int i=;i<=n;i++)
cur[i]=head[i]; ans+=dfs(,INF);
}
return ans;
}
}_din; void Init()
{
mem(dhead,-);
dcnt=-;
mem(head,-);
cnt=-;
} int main()
{
int T;
scanf("%d",&T);
while(T--)
{
Init();
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++)
{
int u,v;
ll w;
scanf("%d%d%lld",&u,&v,&w);
///跑1到其他点的最短路 加正向边
addEdge(u,v,w);
///跑n到其他点的最短路 加反向边
addEdge(v,u,w);
} dij.dij(,n,true);
dij.dij(n,n,false); for(int u=;u<=n;u++)
{
for(int i=dhead[u];~i;i=G[i].next)
{
int v=G[i].v;
ll w=G[i].w;
if(dij.dis[][u]+dij.dis[][v]+w==dij.dis[][n])
{
add(u,v,w);
add(v,u,);
}
}
}
printf("%lld\n",_din.din());
}
}

hdu 6852Path6(最短路+最小割)的更多相关文章

  1. 【bzoj1266】[AHOI2006]上学路线route 最短路+最小割

    题目描述 可可和卡卡家住合肥市的东郊,每天上学他们都要转车多次才能到达市区西端的学校.直到有一天他们两人参加了学校的信息学奥林匹克竞赛小组才发现每天上学的乘车路线不一定是最优的. 可可:“很可能我们在 ...

  2. HDU 5889 Barricade(最短路+最小割)

    http://acm.hdu.edu.cn/showproblem.php?pid=5889 题意: 给出一个图,帝国将军位于1处,敌军位于n处,敌军会选择最短路到达1点.现在帝国将军要在路径上放置障 ...

  3. HDU 5889 Barricade(最短路+最小割水题)

    Barricade Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total ...

  4. hdu 3870(平面图最小割转最短路)

    Catch the Theves Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 65768/32768 K (Java/Others) ...

  5. [2019杭电多校第一场][hdu6582]Path(最短路&&最小割)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6582 题意:删掉边使得1到n的最短路改变,删掉边的代价为该边的边权.求最小代价. 比赛时一片浆糊,赛后 ...

  6. hdu 4289 Control(最小割 + 拆点)

    http://acm.hdu.edu.cn/showproblem.php?pid=4289 Control Time Limit: 2000/1000 MS (Java/Others)    Mem ...

  7. 【求出所有最短路+最小割】【多校第一场】【G题】

    题意 A从1要追在N的 B 只能走最短的路 问B最少切断多少条路可以让A不能过来 问B最多切断多少条路A还是能过来 对于1 求出1到N的所有最短路的路径,对其求最小割 对于2 求出长度最小的最短路即可 ...

  8. BZOJ1266 AHOI2006上学路线(最短路+最小割)

    求出最短路后找出可能在最短路上的边,显然割完边后我们需要让图中这样的边无法构成1到n的路径,最小割即可,非常板子. #include<iostream> #include<cstdi ...

  9. HDU 4859 海岸线(最小割+最大独立点权变形)

    http://acm.hdu.edu.cn/showproblem.php?pid=4859 题意: 欢迎来到珠海!由于土地资源越来越紧张,使得许多海滨城市都只能依靠填海来扩展市区以求发展.作为Z市的 ...

随机推荐

  1. [ 转]Linux进程关系

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! Linux的进程相互之间有一定的关系.比如说,在Linux进程基础中,我们看到,每 ...

  2. 使用 UIWebView 来播放视频

    MPMoviePlayerController 并不是继承自 UIViewController SDK 中的例子使用的是 addSubviews 的方式来添加 MPMoviePlayerControl ...

  3. WPF疑难杂症之二(全屏幕窗口)

    原文:WPF疑难杂症之二(全屏幕窗口) 近日的学习中遇到一个非常奇怪的问题:用XAML文件创建了一个全屏幕窗口,然后,在窗口中建立了一个非常简单的动画.一切都在我的掌控之中,实现非常的顺利. WPF中 ...

  4. TCP之单项通信

    TestServer.java package com.sxt.tcp; /* * 服务端 */ import java.io.DataInputStream; import java.io.IOEx ...

  5. TensorFlow 池化层

    在 TensorFlow 中使用池化层 在下面的练习中,你需要设定池化层的大小,strides,以及相应的 padding.你可以参考 tf.nn.max_pool().Padding 与卷积 pad ...

  6. 2019南昌网络赛-I. Yukino With Subinterval 线段树套树状数组,CDQ分治

    TMD...这题卡内存卡的真优秀... 所以以后还是别用主席树的写法...不然怎么死的都不知道... 树套树中,主席树方法开权值线段树...会造成空间的浪费...这道题内存卡的很紧... 由于树套树已 ...

  7. H3C 命令行帮助特性(续)

  8. winform(C#)里弹出“确定”“取消”对话框

    //消息框中需要显示哪些按钮,此处显示“确定”和“取消” MessageBoxButtons messButton = MessageBoxButtons.OKCancel; //"确定要退 ...

  9. Linux下的一些配置

    /etc/vim/vimrc文件 set cindent set expandtab set smartindent set autoindent set nu set hls taglist安装(t ...

  10. Bootstrap之Form表单验证神器: BootstrapValidator(转)

    前言:做Web开发的我们,表单验证是再常见不过的需求了.友好的错误提示能增加用户体验.博主搜索bootstrap表单验证,搜到的结果大部分都是文中的主题:bootstrapvalidator.今天就来 ...