hdu3416 最短路+最大流

题意:有 n 点 m 边,有出发点 A 到达点 B ,只允许走原图中的最短路,但每条边只允许被走一次,问最多能找出多少条边不重复的最短路

一开始做到的时候瞎做了一发最短路,WA了之后也知道显然不对,就放着了,后来打了今年的多校,再做到的时候发现和多校第一场的1007一样的……最短路+网络流就行了,只不过第一次做这个的时候我还不知道网络流是啥,不会做也正常啦。

首先对于原图跑一遍最短路求出每个点距离 A 点的最短路,然后对于每一条边,如果它的权值等于它连接的两点的最短路的差值的时候,就说明这条路是最短路上的边,将这个边加入网络流的建图中,流量定为1表示这条边只能用一次,这样跑一遍最大流就能直接解决问题了。

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<algorithm>
  4 #include<queue>
  5 #include<vector>
  6 using namespace std;
  7 typedef pair<int,int> pii;
  8 const int maxm=1005;
  9 const int INF=0x3f3f3f3f;
 10
 11 struct cmp{
 12     bool operator()(pii a,pii b){
 13         return a.first>b.first;
 14     }
 15 };
 16
 17 int head[1005],point[100005],val[100005],nxt[100005],size;
 18 bool vis[100005];
 19 int dis[1005],n,s,p,fa[1005],pa[1005];
 20
 21
 22 struct edge{             //弧的结构体,变量:弧的出发点、结束点、容量、流量
 23     int from,to,c,f;
 24     edge(int a,int b,int m,int n):from(a),to(b),c(m),f(n){}
 25 };
 26
 27 struct dinic{
 28     int m,s,t;                    //边数、源点标号、汇点标号
 29     vector<edge>e;        //边
 30     vector<int>g[maxm];    //g[i][j]表示第i个点出发的第j条边在e中的编号
 31     bool vis[maxm];
 32     int d[maxm],cur[maxm];    //d为源点到点的距离,cur为当前遍历到的边
 33     void init(int n){                //初始化,n为点数量(标号0~n-1)
 34         for(int i=0;i<n+5;i++)g[i].clear();
 35         e.clear();
 36     }
 37     void add(int a,int b,int v){        //加入弧和反向弧
 38         e.push_back(edge(a,b,v,0));    //正向弧容量v,反向弧容量0
 39         e.push_back(edge(b,a,0,0));
 40         m=e.size();
 41         g[a].push_back(m-2);
 42         g[b].push_back(m-1);
 43     }
 44     bool bfs(){
 45         memset(vis,0,sizeof(vis));
 46         queue<int>q;
 47         q.push(s);
 48         d[s]=0;
 49         vis[s]=1;
 50         while(!q.empty()){
 51             int u=q.front();q.pop();
 52             for(int i=0;i<g[u].size();i++){
 53                 edge tmp=e[g[u][i]];
 54                 if(!vis[tmp.to]&&tmp.c>tmp.f){
 55                     vis[tmp.to]=1;
 56                     d[tmp.to]=d[u]+1;
 57                     q.push(tmp.to);
 58                 }
 59             }
 60         }
 61         return vis[t];
 62     }
 63     int dfs(int x,int a){
 64         if(x==t||a==0)return a;
 65         int flow=0,f;
 66         for(int& i=cur[x];i<g[x].size();i++){
 67             edge &tmp=e[g[x][i]];
 68             if(d[x]+1==d[tmp.to]&&(f=dfs(tmp.to,min(a,tmp.c-tmp.f)))>0){
 69                 tmp.f+=f;
 70                 e[g[x][i]^1].f-=f;
 71                 flow+=f;
 72                 a-=f;
 73                 if(a==0)break;
 74             }
 75         }
 76         if(!flow)d[x]=-1;
 77         return flow;
 78     }
 79     int mf(int s,int t){                //在主函数中使用的函数,求s到t的最大流
 80         this->s=s;
 81         this->t=t;
 82         int flow=0;
 83         while(bfs()){
 84             memset(cur,0,sizeof(cur));
 85             flow+=dfs(s,INF);
 86         }
 87         return flow;
 88     }
 89 };
 90
 91 void add(int a,int b,int v){
 92     point[size]=b;
 93     val[size]=v;
 94     nxt[size]=head[a];
 95     head[a]=size++;
 96 }
 97
 98 void dij(){
 99     int i;
100     priority_queue<pii,vector<pii>,cmp>q;
101     memset(dis,0x3f,sizeof(dis));
102     memset(fa,-1,sizeof(fa));
103     dis[s]=0;
104     q.push(make_pair(dis[s],s));
105     while(!q.empty()){
106         pii u=q.top();
107         q.pop();
108         if(u.first>dis[u.second])continue;
109         for(i=head[u.second];~i;i=nxt[i]){
110             int j=point[i],v=u.first+val[i];
111             if(!vis[i]&&dis[j]>v){
112                 dis[j]=v;
113                 fa[j]=u.second;
114                 pa[j]=i;
115                 q.push(make_pair(dis[j],j));
116             }
117         }
118     }
119 }
120
121 int main(){
122     int t;
123     scanf("%d",&t);
124     for(int q=1;q<=t;q++){
125         int m,i;
126         memset(head,-1,sizeof(head));
127         memset(vis,0,sizeof(vis));
128         size=0;
129         scanf("%d%d",&n,&m);
130         for(i=1;i<=m;i++){
131             int a,b,v;
132             scanf("%d%d%d",&a,&b,&v);
133             if(a!=b){
134                 add(a,b,v);
135             }
136         }
137         scanf("%d%d",&s,&p);
138         dinic d;
139         dij();
140         for(i=1;i<=n;++i){
141             for(int j=head[i];~j;j=nxt[j]){
142                 int k=point[j];
143                 if(dis[i]+val[j]==dis[k])d.add(i,k,1);
144             }
145         }
146         printf("%d\n",d.mf(s,p));
147     }
148     return 0;
149 }

时间: 2024-10-10 18:12:00

hdu3416 最短路+最大流的相关文章

BZOJ 3931: [CQOI2015]网络吞吐量( 最短路 + 最大流 )

最短路 + 最大流 , 没什么好说的... 因为long long WA 了两次.... ------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<vector> #include<iostre

hdu5294||2015多校联合第一场1007 最短路+最大流

http://acm.hdu.edu.cn/showproblem.php?pid=5294 Problem Description Innocent Wu follows Dumb Zhang into a ancient tomb. Innocent Wu's at the entrance of the tomb while Dumb Zhang's at the end of it. The tomb is made up of many chambers, the total numb

hdu3416 Marriage Match IV【最短路+最大流】

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3416 题目描述:求起点到终点一共有多少完全不同的最短路径(最短路径之间不能有公共边) 思路:先用dijkstra求出起点到终点的最短路,然后用可以成为最短路径的边(dis[终]-dis[始]==权值)建立网络,容量为1.最后只需求出以起点为源点终点为汇点的最大流即可 #include <iostream> #include <ios> #include <iomanip>

hdu3416 Marriage Match IV 最短路+ 最大流

此题的大意:给定一幅有向图,求起点到终点(都是固定的)的不同的最短路有多少条.不同的最短路是说不能有相同的边,顶点可以重复.并且图含有平行边. 看了题以后,就想到暴力,但是暴力往往是不可取的.(暴力的最坏情况下的时间复杂度是O(n^3)).我说的暴力是求一次最短路以后,把最短路上的边全部去掉(权值设为INF). 最短路可以有很多条,但是最短路的值只有一个.根据这个,我们可以判断某条边是否在最短路上. 建图(单向边),求最短路,起点就是输入的起点.枚举每一条边,如果满足dist[i]+Map[i]

hdu3461Marriage Match IV 最短路+最大流

//给一个图.给定起点和终点,仅仅能走图上的最短路 //问最多有多少种走的方法.每条路仅仅能走一次 //仅仅要将在最短路上的全部边的权值改为1.求一个最大流即可 #include<cstdio> #include<cstring> #include<iostream> #include<queue> #include<vector> using namespace std ; const int inf = 0x3f3f3f3f ; const

BZOJ2324 ZJOI2011 营救皮卡丘 最短路+费用流

题意:给定一张无向图,有K个人,每一时刻K个人可以同时走(也可以停在一个节点),在到达i之前必须先到达i-1,求从0到N,K个人走的最小距离和(只需一个人到达即可) 题解: 用Floyd跑出任意两个城市i j间的最短路,更新的前提是k<j(要到达城市j必须先到达1->j-1) 将每个城市拆成两个点A B,u v间连费用为w的边,i为任意一个城市,按如下方式建图: 从A向B连流量为INF费用为0的边,表示一个城市可以经过多次 从S向0B连流量为K费用为0的边,表示最初有K个人从0出发 从iB向T

O - Marriage Match IV - hdu 3416(最短路+最大流)

题目大意:在城市A的男孩想去城市B的女孩,不过他去城市B必须走最短路,并且走过的路不可以再走,问他最多能看这个女孩多少次.   分析:因为这个男孩直走最短路,所以我们必须求出来所有最短路径上的路,怎么判断一条路是否属于最短路经上的呢?其实比较容易的,只要先求出来从A到达所有点的最短路distA[x], 然后再求出来所有点到B的最短路distB[y](添加反边从B开始即可求出),如果x-y之间有一条路,那么只需要判断distA[x]+distB[y]+w(x,y) == distA[B] 是否成立

HDU 3416 Marriage Match IV(最短路+最大流)

HDU 3416 Marriage Match IV 题目链接 题意:给一个有向图,给定起点终点,问最多多少条点可以重复,边不能重复的最短路 思路:边不能重复,以为着每个边的容量就是1了,最大流问题,那么问题只要能把最短路上的边找出来,跑一下最大流即可,判断一条边是否是最短路上的边,就从起点和终点各做一次dijstra,求出最短路距离后,如果一条边满足d1[u] + d2[v] + w(u, v) == Mindist,那么这条边就是了 代码: #include <cstdio> #inclu

【BZOJ-3931】网络吞吐量 最短路 + 最大流

3931: [CQOI2015]网络吞吐量 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1228  Solved: 524[Submit][Status][Discuss] Description 路由是指通过计算机网络把信息从源地址传输到目的地址的活动,也是计算机网络设计中的重点和难点.网络中实现路由转发的硬件设备称为路由器.为了使数据包最快的到达目的地,路由器需要选择最优的路径转发数据包.例如在常用的路由算法OSPF(开放式最短路径优先)中