题意:n个点,m条边,构建有权无向图。求出删去最少条边数没有最短路,以及删出最多条边,使最短路的长度不变。
思路:先处理出最短路,然后使用结果的dis数组,若dis[v]-dis[u] = w(u,v),则该路就是最短路经中的一条边。建出最短路径之后跑最大流,流量是有多少边权相同的重边,跑出来就是最小割,也就是阻断所有最短路的最小花费。最后再跑最短路,边权为1,跑出来的最短路dis[n],就是所需边最少的最短路。
补充:在优化理论中,最大流最小割定理指:在一个网络流中,能够从源点到达汇点的最大流量,等于,如果从网络中移除就能够导致网络流中断的边的集合的最小容量和。
#include <bits/stdc++.h> using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef pair<int, int> PI; typedef pair< PI, int> PII; const double eps=1e-5; const double pi=acos(-1.0); const int mod=1e9+7; const int INF=0x3f3f3f3f; const int mx=1100; #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 const int MAXN = 2100+50; const int MAXM = 60000*2+500; struct Edge { int to,next,cap,flow; } edge[MAXM]; int tol; int head[MAXN]; int gap[MAXN],dep[MAXN],cur[MAXN]; void init() { tol = 0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int w,int rw = 0) { edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0; edge[tol].next = head[u]; head[u] = tol++; edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0; edge[tol].next = head[v]; head[v] = tol++; } int Q[MAXN]; void BFS(int start,int end) { memset(dep,-1,sizeof(dep)); memset(gap,0,sizeof(gap)); gap[0] = 1; int front = 0, rear = 0; dep[end] = 0; Q[rear++] = end; while(front != rear) { int u = Q[front++]; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(dep[v] != -1)continue; Q[rear++] = v; dep[v] = dep[u] + 1; gap[dep[v]]++; } } } int S[MAXN]; int sap(int start,int end,int N) { BFS(start,end); memcpy(cur,head,sizeof(head)); int top = 0; int u = start; int ans = 0; while(dep[start] < N) { if(u == end) { int Min = INF; int inser; for(int i = 0; i < top; i++) if(Min > edge[S[i]].cap - edge[S[i]].flow) { Min = edge[S[i]].cap - edge[S[i]].flow; inser = i; } for(int i = 0; i < top; i++) { edge[S[i]].flow += Min; edge[S[i]^1].flow -= Min; } ans += Min; top = inser; u = edge[S[top]^1].to; continue; } bool flag = false; int v; for(int i = cur[u]; i != -1; i = edge[i].next) { v = edge[i].to; if(edge[i].cap - edge[i].flow && dep[v]+1 == dep[u]) { flag = true; cur[u] = i; break; } } if(flag) { S[top++] = cur[u]; u = v; continue; } int Min = N; for(int i = head[u]; i != -1; i = edge[i].next) if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min) { Min = dep[edge[i].to]; cur[u] = i; } gap[dep[u]]--; if(!gap[dep[u]])return ans; dep[u] = Min + 1; gap[dep[u]]++; if(u != start)u = edge[S[--top]^1].to; } return ans; } bool vis[MAXN]; int pre[MAXN]; void Dijkstra(int cost[][MAXN],int lowcost[],int n,int beg) { for(int i=0; i<n; i++) { lowcost[i]=INF; vis[i]=false; pre[i]=-1; } lowcost[beg]=0; for(int j=0; j<n; j++) { int k=-1; int Min=INF; for(int i=0; i<n; i++) if(!vis[i]&&lowcost[i]<Min) { Min=lowcost[i]; k=i; } if(k==-1)break; vis[k]=true; for(int i=0; i<n; i++) if(!vis[i]&&lowcost[k]+cost[k][i]<lowcost[i]) { lowcost[i]=lowcost[k]+cost[k][i]; pre[i]=k; } } } int cost[MAXN][MAXN]; int dis[MAXN]; int num[MAXN][MAXN]; int cost2[MAXN][MAXN]; int dis2[MAXN]; void initia(int n) { init(); for(int i=0; i<=n; ++i) { for(int j=0; j<=n; ++j) { cost[i][j]=INF; num[i][j]=0; cost2[i][j]=INF; } cost[i][i]=0; cost2[i][i]=0; } } int main() { int n,m; int u,v,w; while(~scanf("%d%d",&n,&m)) { initia(n); for(int i=0; i<m; ++i) { scanf("%d%d%d",&u,&v,&w); u--; v--; if(cost[u][v]>w) { cost[u][v]=w; cost[v][u]=w; num[u][v]=1; num[v][u]=1; } else if(cost[u][v]==w) { num[u][v]++; num[v][u]++; } } Dijkstra(cost,dis,n,0); for(int i=0; i<n; ++i) { for(int j=0; j<n; ++j) { if(i==j) continue; if(dis[j]-dis[i]==cost[i][j]) { addedge(i,j,num[i][j]); cost2[i][j]=1; } } } Dijkstra(cost2,dis2,n,0); printf("%d %d\n",sap(0,n-1,n),m-dis2[n-1]); } return 0; }
- 版权声明:本文基于《知识共享署名-相同方式共享 3.0 中国大陆许可协议》发布,转载请遵循本协议
- 文章链接:http://www.carlstedt.cn/archives/1049 (转载时请注明本文出处及文章链接)
发表评论
快来吐槽一下吧!