图论测试2 t1 幻想乡的异变 SPFA+最大流
来源:互联网 发布:苹果电脑音频剪辑软件 编辑:程序博客网 时间:2024/05/02 02:52
考试的时候以为是费用流,于是花了二十几分钟兴致勃勃地打完光荣T掉。。。
后来评讲的时候发现是SPFA+最大流。
对于每个点,先求出1到这个点的最小距离,再求出这个点到n的最小距离,然后枚举每一条边,如果从1到这条边的起始点距离+这条边的边权+这条边的终点到n的距离==1到n的最短路的话,说明这条路就可能出现在1到n的最短路上,流量=1。
最后跑最大流就可以求出最多有多少条满足最短路的路径可以到达终点n。
关于如何求1到各个点与各个点到n的最短路:
从1到n的最短路就用SPFA,从各个点到n可以转化为从n到各个点,所以存反向边,再以n为起点跑一遍SPFA。但由于原图中边是有向的,所以反向边的存在可能会对最短路造成影响:
eg:从1到2有一条200的路,从2到1有一条15的路。
从1到2的最短路是200,但如果不判反向边,最短路就会变成15。所以每次更新时要判一下。
这道题的想法之前学长有讲过一道题很像,就是关于判断这条路在不在最短路上。感觉特别强2333。
#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<queue>#define ms(x,y) memset(x,y,sizeof(x))#define ll long long#define INF 233333333using namespace std;const int N = 500010;int n,m;int num=1;int head[N];inline int Min(int a,int b){ return a<b?a:b;}struct node{ int pre,u,v,w,f;}edge[N];void addedge(int from,int to,int w){ num++; edge[num].pre=head[from]; edge[num].v=to; edge[num].u=from; edge[num].f=0; edge[num].w=w; head[from]=num;}deque<int> q;ll dis[N][2];bool vis[N];void spfa(int s,int t,int x){ q.push_back(s);dis[s][x]=0;vis[s]=true; while(!q.empty()){ int u=q.front();q.pop_front(); vis[u]=false; for(int i=head[u];i;i=edge[i].pre){ int v=edge[i].v; if((i&1)==x&&dis[v][x]>dis[u][x]+edge[i].w){ dis[v][x]=dis[u][x]+edge[i].w; if(!vis[v]){ vis[v]=true; if(!q.empty()&&dis[v][x]<dis[q.front()][x]) q.push_front(v); else q.push_back(v); } } } }}int dist[N];queue<int> q1;bool bfs(){ vis[1]=true;q1.push(1); while(!q1.empty()){ int u=q1.front();q1.pop(); for(int i=head[u];i;i=edge[i].pre){ int v=edge[i].v; if(!vis[v]&&edge[i].f){ dist[v]=dist[u]+1; vis[v]=true; q1.push(v); } } } if(vis[n]) return true; return false;}int dfs(int u,int delta){ if(u==n||delta==0) return delta; int ans=0; for(int i=head[u];i&δi=edge[i].pre){ int v=edge[i].v; if(dist[v]==dist[u]+1&&edge[i].f){ int dd=dfs(v,Min(edge[i].f,delta)); edge[i].f-=dd; edge[i^1].f+=dd; ans+=dd; delta-=dd; } } if(!ans) dist[u]=-1; return ans;}void zero(){ ms(dist,0);ms(vis,0); while(!q1.empty()) q1.pop();}int maxflow(){ int ans=0; while(1){ zero(); if(!bfs()) break;//此处有可能搜不到n。 ans+=dfs(1,INF); } return ans;}int main(){ freopen("change.in","r",stdin); freopen("change.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); addedge(v,u,w); } ms(dis,127);ms(vis,0); spfa(1,n,0); ms(vis,0);while(!q.empty()) q.pop_front(); spfa(n,1,1); for(int i=2;i<=num;i+=2){ int u=edge[i].u,v=edge[i].v; if(dis[u][0]+edge[i].w+dis[v][1]==dis[n][0]){ edge[i].f=1; } } printf("%d",maxflow()); return 0;}
阅读全文
0 0
- 图论测试2 t1 幻想乡的异变 SPFA+最大流
- 7.12图论练习赛 T1 幻想乡的异变 (SPFA + 网络流)
- 图论测试2 t3 幻想乡的例大祭 Tarjan+SPFA
- 图论测试2 t2 幻想乡的符卡 二分答案+最大流
- 7.12图论练习赛 T3 幻想乡的例大祭 (tarjan + SPFA)
- 软件测试的幻想
- 7.12图论练习赛 T2 幻想乡的符卡 (网络流最小割)
- BZOJ3931【最大流】【SPFA】
- 最小费用最大流,SPFA
- bzoj 3931(spfa+最大流)
- hihocoder 1145 幻想乡的日常
- bzoj3926诸神眷顾的幻想乡
- BZOJ3925: [Zjoi2015]地震后的幻想乡
- bzoj4596: [Shoi2016]黑暗前的幻想乡
- BZOJ4596 [Shoi2016]黑暗前的幻想乡
- 【ZJOI2015】诸神眷顾的幻想乡
- 【ZJOI2015】诸神眷顾的幻想乡
- 4596: [Shoi2016]黑暗前的幻想乡
- Android如何获取手机本机号码
- Android Error:Execution failed for task ':app:dataBindingProcessLayoutsDebug'
- AlertDialog 背景颜色透明设置
- stm32配置spi
- megacli 管理 ceph 存储常用脚本
- 图论测试2 t1 幻想乡的异变 SPFA+最大流
- 基本数据类型
- java基础知识精讲视频教程百度云盘分享!
- 【面经笔记】进程间通信方式、线程同步机制
- css div 居中
- 数组的拆分函数array_chunk()
- C语言:循环的嵌套
- 7.12图论练习赛 T1 幻想乡的异变 (SPFA + 网络流)
- PHP获取某周某一的方法