2016 计蒜之道 复赛 菜鸟物流的运输网络【拆点+思维建图+网络流】
来源:互联网 发布:cf for mac版 编辑:程序博客网 时间:2024/04/30 23:25
菜鸟物流有自己的运输网络,网络中包含 n 个城市物流集散中心,和 m 对城市之间的运输线路(线路是双向的)。菜鸟物流允许淘宝卖家自行确定包裹的运输路径,但只有一条限制规则:不允许经过重复的城市。淘宝卖家小明从 a 城市寄出快递后,希望包裹在 mid 城市进行包装加工以后再寄往 b 城市。
现在小明希望算出一个满足他需求的合法运输路径,你可以帮他算出来么?
已知这样的方案一定存在。请为小明输出任意一个可行方案。
输入格式
第一行一个正整数 T(1≤T≤10) 表示数据的组数。
每组数据第一行 2 个正整数 n,m(3≤n≤100,m≤2n(n−1)),表示城市个数和运输线路数目。
第二行 3 个互不相同正整数 a,b,mid(1≤a,b,mid≤n),表示起点、终点和途径城市。
接下来 m 行,每行 2 个正整数 x,y(1≤x,y≤n),表示每条线路连接的 2 个城市。
每组数据一定存在至少一组合法方案。如果有多种满足小明需求的合法运输路径,输出任意一个即可。
输出格式
每组数据输出 L 个正整数,表示顺次经过的城市的编号,包括起点和终点。每两个整数之间一个空格,最后一个整数后面没有空格。
样例输入
15 51 5 31 22 33 44 55 1
样例输出
1 2 3 4 5
思路:
题目描述以及数据范围很爆做法。
很显然一道拆点网络流问题。
那么如何考虑从u到v一定经过mid这个点呢?
我们不妨从mid出发,找一条从mid到u的路径,再找一条从mid到v的路径,将其合并即可。
那么我们建图方式也就很简单了:
①设定源点,将其连入mid这个点,流为2.
②设定汇点,将u和v两个点连入汇点,流为1.
③对于输入的无向边,我们将其连入,流为INF.
④然后拆点,除了mid这个点之外,每个点i拆出来一个点i+n,然后从i到i+n建一条边,流为1
然后建好图之后跑完网络流之后,我们直接O(nm)倒序查询路径即可。
查询路径过程我们直接访问退回边的信息就行了。
Ac代码:
#include<stdio.h>#include<string.h>#include<queue>#include<stack>#include<iostream>using namespace std;struct node{ int from; int to; int w; int next;}e[1500000];int cur[1500];int divv[1500];int head[1500];int n,m,cont;int tmpx,tmpy,tmpz,ss,tt;void add(int from,int to,int w){ e[cont].from=from; e[cont].to=to; e[cont].w=w; e[cont].next=head[from]; head[from]=cont++;}void Getmap(){ cont=0; memset(head,-1,sizeof(head)); ss=n*2+1; tt=ss+1; add(ss,tmpz,2); add(tmpz,ss,0); for(int i=1;i<=n;i++) { if(i==tmpz) { add(i,i+n,2); add(i+n,i,0); continue; } add(i,i+n,1); add(i+n,i,0); if(i==tmpx||i==tmpy) { add(i+n,tt,1); add(tt,i+n,0); } } for(int i=0;i<m;i++) { int u,v; scanf("%d%d",&u,&v); add(u+n,v,0x3f3f3f3f); add(v,u+n,0); add(v+n,u,0x3f3f3f3f); add(u,v+n,0); }}int makedivv(){ queue<int >s; s.push(ss); memset(divv,0,sizeof(divv)); divv[ss]=1; while(!s.empty()) { int u=s.front(); if(u==tt)return 1; s.pop(); for(int i=head[u];i!=-1;i=e[i].next) { int v=e[i].to; int w=e[i].w; if(w&&divv[v]==0) { divv[v]=divv[u]+1; s.push(v); } } } return 0;}int Dfs(int u,int maxflow,int tt){ int ret=0; if(u==tt)return maxflow; for(int &i=cur[u];i!=-1;i=e[i].next) { int v=e[i].to; int w=e[i].w; if(w&&divv[v]==divv[u]+1) { int f=Dfs(v,min(maxflow-ret,w),tt); e[i].w-=f; e[i^1].w+=f; ret+=f; if(ret==maxflow)return ret; } } return ret;}void Dinic(){ while(makedivv()==1) { memcpy(cur,head,sizeof(head)); Dfs(ss,0x3f3f3f3f,tt); }}void Slove(){ queue<int >ans; int now=tmpx; while(1) { if(now<=n&&now>=1) { //printf("%d\n",now); ans.push(now); } int pos=-1; for(int i=0;i<cont;i++) { if(e[i].to==now) { if(e[i^1].w>0) { pos=e[i].from; break; } } } if(pos==ss)break; now=pos; } now=tmpy; stack<int >ans2; while(1) { if(now<=n&&now>=1) { //printf("%d\n",now); ans2.push(now); } int pos=-1; for(int i=0;i<cont;i++) { if(e[i].to==now) { if(e[i^1].w>0) { pos=e[i].from; break; } } } if(pos==tmpz)break; now=pos; } int flag=0; while(!ans.empty()) { if(flag>0)printf(" "); printf("%d",ans.front()); ans.pop(); flag++; } while(!ans2.empty()) { if(flag>0)printf(" "); printf("%d",ans2.top()); ans2.pop(); flag++; } printf("\n"); /* for(int i=0;i<cont;i++) { if(e[i].to==8&&e[i].from==3) { printf("%d\n",e[i^1].w); } } */}int main(){ int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); scanf("%d%d%d",&tmpx,&tmpy,&tmpz); Getmap(); Dinic(); Slove(); }}
- 2016 计蒜之道 复赛 菜鸟物流的运输网络【拆点+思维建图+网络流】
- [网络流] 2016 计蒜之道 复赛 菜鸟物流的运输网络
- 计蒜之道复赛F题 菜鸟物流的运输网络(网络流)
- 计蒜之道 2016 复赛 F.菜鸟物流的运输网络
- 2016计蒜之道复赛 菜鸟物流的运输网络
- 计蒜客 菜鸟物流的运输网络
- 计蒜客 菜鸟物流的运输网络
- [并查集 || 点分治 树重心] 2015 计蒜之道 复赛 京东的物流路径
- 计蒜客 菜鸟物流的运输网络 解题报告
- 2016 计蒜之道 复赛 A
- 2017 计蒜之道 复赛 百度地图导航 (拆点+最短路)
- 2017 计蒜之道 复赛 百度地图导航【思维+最短路】
- 2016计蒜之道复赛 微信钱包付款
- 2016 计蒜之道 复赛 题解 部分
- 2017计蒜之道 复赛 BDF
- 2017 计蒜之道 复赛 题解
- 2016 计蒜之道 复赛 一些简单题的Solution
- 2016计蒜之道 复赛 A. 百度地图的实时路况(cdq分治+floyd)
- Linux ps命令详解与示例说明
- redhat linux 7 创建udev
- 煮酒闲谈
- JQuery文件
- 同一个标签,可以添加多个事件(如多个click),那么执行顺序是怎么样的呢?
- 2016 计蒜之道 复赛 菜鸟物流的运输网络【拆点+思维建图+网络流】
- 商品展示
- js中检测数据类型
- 压测-sysbench安装
- 带你解锁蓝牙skill(二)
- WebViewClient
- gitlab解决#<Unicorn::HttpServer:0x007f854b8b8ad0>: worker (pid: 29607) exceeds memory limit
- 细说ftp服务器的搭建部署及权限管理
- Android静默拍照(无感知拍照)