HDU 3416 Marriage Match IV (最短路建图+最大流)
题目分析
题意:给出一个有n个结点,m条单向边的有向图,问从源点s到汇点t的不重合的最短路有多少条,所谓不重复,意思是任意两条最短路径都不共用一条边,而且任意两点之间的边只会用一条。
思路:没有看出是最大流的话,可能会止步于用dijkstra得到所有的所有最短路包含的边,但是无法确定最多有多少条路。
但是学过网络流的人走到这一步就会想到这里需要用最大流求解:我们将每一条最短路上的边构成新的图,这个图中的边的边权都是1,在这个由最短路中的边组成的图中,求得的s-t最大流即为我们所求的答案。
代码区
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<string> #include<fstream> #include<vector> #include<stack> #include <map> #include <iomanip> #define bug cout << "**********" << endl #define show(x, y) cout<<"["<<x<<","<<y<<"] " #define LOCAL = 1; using namespace std; typedef long long ll; const int inf = 0x3f3f3f3f; const ll mod = 998244353; const int Max = 1e5 + 10; const int Max2 = 1e3+10; struct Edge { int to,next,flow; }edge1[Max<<1],edge2[Max<<1],edge[Max<<1]; int T, n, m, s, t; int head1[Max2],tot1; int head2[Max2],tot2; int dis_s[Max2],dis_t[Max2]; //某结点距离源点和始点的最近距离 bool vis[Max2]; int head[Max2],tot; int dis[Max]; void init() { memset(head1,-1,sizeof(head1));tot1 = 0; memset(head2,-1,sizeof(head2));tot2 = 0; memset(head,-1,sizeof(head));tot = 0; memset(dis_s,inf,sizeof(dis_s)); memset(dis_t,inf,sizeof(dis_t)); } void add1(int u, int v,int dist) //原图的边 { edge1[tot1].to = v; edge1[tot1].flow = dist; edge1[tot1].next = head1[u]; head1[u] = tot1++; edge2[tot2].to = u; edge2[tot2].flow = dist; edge2[tot2].next = head2[v]; head2[v] = tot2++; } void add2(int u,int v,int flow) //跑最大流的图 { edge[tot].to = v; edge[tot].flow = flow; edge[tot].next = head[u]; head[u] = tot++; } void dfs_s() { priority_queue<pair<int,int> > q; memset(vis,0,sizeof(vis)); q.push(make_pair(0,s)); dis_s[s] = 0; while(!q.empty()) { int u = q.top().second;q.pop(); if(vis[u]) continue; vis[u] = true; for(int i = head1[u] ;i != -1;i = edge1[i].next) { int v = edge1[i].to; if(!vis[v] && dis_s[v] > dis_s[u] + edge1[i].flow) //这里的flow就是边权,和网络流的图公用一个结构体 { dis_s[v] = dis_s[u] + edge1[i].flow; q.push(make_pair(-dis_s[v],v)); } } } } void dfs_t() { priority_queue<pair<int,int> > q; memset(vis,0,sizeof(vis)); q.push(make_pair(0,t)); dis_t[t] = 0; while(!q.empty()) { int u = q.top().second;q.pop(); if(vis[u]) continue; vis[u] = true; for(int i = head2[u] ;i != -1;i = edge2[i].next) { int v = edge2[i].to; if(!vis[v] && dis_t[v] > dis_t[u] + edge2[i].flow) //这里的flow就是边权,和网络流的图公用一个结构体 { dis_t[v] = dis_t[u] + edge2[i].flow; q.push(make_pair(-dis_t[v],v)); } } } } bool bfs() { memset(dis,-1,sizeof(dis)); queue<int>q; q.push(s);dis[s] = 0; while(!q.empty()) { int u = q.front();q.pop(); for(int i = head[u]; i != -1 ; i = edge[i].next) { int v = edge[i].to; if(edge[i].flow > 0 && dis[v] == -1) { dis[v] = dis[u] + 1; if(v == t) return true; q.push(v); } } } return false; } int dfs(int u, int flow_in) { if(u == t) return flow_in; int flow_out = 0; for(int i = head[u] ; i != -1; i = edge[i].next) { int v= edge[i].to; if(edge[i].flow > 0 && dis[v] == dis[u] + 1) { int flow = dfs(v,min(flow_in,edge[i].flow)); if(flow == 0) continue; flow_in -= flow; flow_out += flow; edge[i].flow -= flow; edge[i^1].flow += flow; if(flow_in == 0) break; } } return flow_out; } int Dinic() { int sum = 0; while(bfs()) { sum += dfs(s,inf); } return sum; } int main() { #ifdef LOCAL //freopen("input.txt", "r", stdin); //freopen("output.txt", "w", stdout); #endif scanf("%d",&T); while(T--) { init(); scanf("%d%d",&n,&m); for(int i = 1, u, v, dis;i <= m; i ++) { scanf("%d%d%d",&u,&v,&dis); if(u != v) add1(u,v,dis); } scanf("%d%d",&s,&t); dfs_s(); dfs_t(); for(int u = 1;u <= n ;u ++) { for(int i =head1[u]; i != -1; i =edge1[i].next) { int v = edge1[i].to; int flow = edge1[i].flow; if(dis_s[u] + dis_t[v] + flow == dis_s[t]) //这条边为最短路上的边 { add2(u,v,1);add2(v,u,0); } } } printf("%d\n",Dinic()); } return 0; }