HDU 5294 Tricks Device(spfa+最大流-Dinic)
2015-08-11 17:01
162 查看
Description
给你n个墓室,m条路径,一个人在1号墓室(起点),另一个人在n号墓室(终点),起点的那个人只有通过最短路径才能追上终点的那个人,而终点的那个人能切断任意路径。
第一问:终点那人要使起点那人不能追上的情况下可以切的最少的路径数,输出最少的路径数
第二问:起点那人能追上终点那人的情况下,终点那人能切断的最多的路径数,输出最多的路径数
Input
多组用例,每组用例第一行两个整数N和M表示点数和边数,之后M行每行三个整数a,b,c表示a点和b点之间有一条边权为c的边,以文件尾结束输入
Output
对于每组用例,输出两问的答案
Sample Input
8 9
1 2 2
2 3 2
2 4 1
3 5 3
4 5 4
5 8 1
1 6 2
6 7 5
7 8 1
Sample Output
2 6
Solution
首先两遍spfa求出第一个点到所有点的最短距离以及最后一个点到所有点的最短距离,求出所有最短路后以最短路为边,每条边容量为1建立新图,对新图求出最大流即为第一问答案,对新图spfa后得到第一个点到最后一个点的最短距离即为边数最少的最短路的边数,用总边数减去这个值即为第二问答案
Code
给你n个墓室,m条路径,一个人在1号墓室(起点),另一个人在n号墓室(终点),起点的那个人只有通过最短路径才能追上终点的那个人,而终点的那个人能切断任意路径。
第一问:终点那人要使起点那人不能追上的情况下可以切的最少的路径数,输出最少的路径数
第二问:起点那人能追上终点那人的情况下,终点那人能切断的最多的路径数,输出最多的路径数
Input
多组用例,每组用例第一行两个整数N和M表示点数和边数,之后M行每行三个整数a,b,c表示a点和b点之间有一条边权为c的边,以文件尾结束输入
Output
对于每组用例,输出两问的答案
Sample Input
8 9
1 2 2
2 3 2
2 4 1
3 5 3
4 5 4
5 8 1
1 6 2
6 7 5
7 8 1
Sample Output
2 6
Solution
首先两遍spfa求出第一个点到所有点的最短距离以及最后一个点到所有点的最短距离,求出所有最短路后以最短路为边,每条边容量为1建立新图,对新图求出最大流即为第一问答案,对新图spfa后得到第一个点到最后一个点的最短距离即为边数最少的最短路的边数,用总边数减去这个值即为第二问答案
Code
#include<cstdio> #include<iostream> #include<cstring> #include<queue> using namespace std; #define maxn 3333 #define maxm 555555 #define INF 0x3f3f3f3f int head[maxn],cur[maxn],d[maxn],st[maxm],s,e,no; struct point { int u,v,flow,next; point(){}; point(int x,int y,int z,int w):u(x),v(y),next(z),flow(w){}; }p[maxm]; void add(int x,int y,int z) { p[no]=point(x,y,head[x],z); head[x]=no++; p[no]=point(y,x,head[y],0); head[y]=no++; } void init() { memset(head,-1,sizeof(head)); no=0; } bool bfs() { int i,x,y; queue<int>q; memset(d,-1,sizeof(d)); d[s]=0; q.push(s); while(!q.empty()) { x=q.front(); q.pop(); for(i=head[x];i!=-1;i=p[i].next) { if(p[i].flow&& d[y=p[i].v]<0) { d[y]=d[x]+1; if(y==e) return true; q.push(y); } } } return false; } int dinic() { int i,loc,top,x=s,nowflow,maxflow=0; while(bfs()) { for(i=s;i<=e;i++) cur[i]=head[i]; top=0; while(true) { if(x==e) { nowflow=INF; for(i=0;i<top;i++) { if(nowflow>p[st[i]].flow) { nowflow=p[st[i]].flow; loc=i; } } for(i=0;i<top;i++) { p[st[i]].flow-=nowflow; p[st[i]^1].flow+=nowflow; } maxflow+=nowflow; top=loc; x=p[st[top]].u; } for(i=cur[x];i!=-1;i=p[i].next) if(p[i].flow&&d[p[i].v]==d[x]+1) break; cur[x]=i; if(i!=-1) { st[top++]=i; x=p[i].v; } else { if(!top) break; d[x]=-1; x=p[st[--top]].u; } } } return maxflow; } struct node { int to; int w; int next; }edge[maxm]; int head1[maxn],tol; int N,M; int dis1[maxn],dis2[maxn]; int a[66666][3],b[66666][2]; void init1()//初始化 { memset(head1,-1,sizeof(head1)); tol=0; } void add1(int u,int v,int c)//建边 { edge[tol].w=c; edge[tol].to=v; edge[tol].next=head1[u]; head1[u]=tol++; } void spfa(int s,int n)//单源最短路,s是起点,n是点数 { bool vis[maxn]; memset(vis,false,sizeof(vis)); queue<int>que; for(int i=0;i<=n;i++) dis1[i]=INF; dis1[s]=0; vis[s]=true; que.push(s); while(!que.empty()) { int u=que.front(); que.pop(); vis[u]=false; for(int i=head1[u];i!=-1;i=edge[i].next) { int v=edge[i].to; int w=edge[i].w; if(dis1[v]>dis1[u]+w) { dis1[v]=dis1[u]+w; if(!vis[v]) { vis[v]=true; que.push(v); } } } } } int main() { int N,M; while(~scanf("%d%d",&N,&M)) { init1();//初始化 for(int i=0;i<M;i++) { scanf("%d%d%d",&a[i][0],&a[i][1],&a[i][2]); //建双向边 add1(a[i][0],a[i][1],a[i][2]); add1(a[i][1],a[i][0],a[i][2]); } spfa(1,N);//源点到所有点的最短距离 for(int i=1;i<=N;i++)//将dis1存储的最短距离复制到dis2中 dis2[i]=dis1[i]; spfa(N,N);//汇点到所有点的最短距离 int n=0; for(int i=0;i<M;i++)//找到所有最短路并将其存储在b数组中 { if(dis2[a[i][0]]>dis2[a[i][1]]) swap(a[i][0],a[i][1]); if(dis2 ==dis2[a[i][0]]+a[i][2]+dis1[a[i][1]]) { b [0]=a[i][0]; b [1]=a[i][1]; n++; } } init();//初始化 s=1;//源点为1 e=N;//汇点为N for(int i=0;i<n;i++)//对所有最短路的起点和终点建容量为1的边 add(b[i][0],b[i][1],1); int ans1=dinic();//第一问答案即为新图的最大流 init1();//初始化 for(int i=0;i<n;i++) { //建双向边,边权均为1 add1(b[i][0],b[i][1],1); add1(b[i][1],b[i][0],1); } spfa(1,N);//求点1到所有点的最短距离 int ans2=M-dis1 ;//总边数减去新图起点终点最短距离即为第二问答案 printf("%d %d\n",ans1,ans2); } return 0; }
相关文章推荐
- 《机器学习实战》(三)决策树(decision trees)
- SQLite数据存储
- Android-加速传感器或者OrientationEventListener做横竖屏切换
- android--访问网络权限
- POCO C++库学习和分析——任务
- 技术文档
- js apply/call/caller/callee/bind使用方法与区别分析
- CC2541的几种工作状态
- python爬虫 scrapy框架 知乎zhihu 模拟登陆
- 【leetcode】Recover Binary Search Tree
- python logging
- HDU 5374 模拟俄罗斯方块
- 通过SQLServer的数据库邮件来发送邮件
- poj 1789 Truck History【最小生成树prime】
- 进程及线程(2)
- RHEL 6.6搭建hadoop 2.x集群环境
- MySQL Study之--MySQL关闭自动commit(autocommit)
- 查看 Linux 是32位还是64位的
- Ubuntu 12.04.1安装glusterfs-3.6.4
- 黑马程序员——C语言笔记之函数