【求出所有最短路+最小割】【多校第一场】【G题】
题意
A从1要追在N的 B 只能走最短的路
问B最少切断多少条路可以让A不能过来
问B最多切断多少条路A还是能过来
对于1 求出1到N的所有最短路的路径,对其求最小割
对于2 求出长度最小的最短路即可
如何求所有最短路呢 利用这个
void dfs(int s,int ans) { if(s==N) { ANS2=min(ans,ANS2); return ; } for(EDGE *p=Graph[s].first;p;p=p->next) { if(dist[s]+p->w==dist[p->to]) { if(VISIT[s]==0) { VISIT[s]=1;nn++;} if(VISIT[p->to]==0) { VISIT[p->to]=1;nn++;} addedge(s,p->to,1,0); dfs(p->to,ans+1); } } }即这个判断来判断所有路径
if(dist[s]+p->w==dist[p->to])
#include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <ctime> #include <algorithm> #include <iostream> #include <sstream> #include <string> #define oo 0x13131313 using namespace std; const int maxn=5000; int visit[maxn]; int dist[maxn]; int VISIT[maxn]; int N,m; struct EDGE{ int w; int to; EDGE *next; }E[300000],*EE; struct node{ EDGE *first; }Graph[maxn]; //网络流 const int MAXN=4000+5; const int MAXM=300000; const int INF=0x3f3f3f3f; int nn=0; int ANS2=0x3f3f3f3f; struct Edge { int to,next,cap,flow; void get(int a,int b,int c,int d) { to=a;next=b;cap=c;flow=d; } }edge[MAXM]; int tol; int head[MAXN]; int gap[MAXN],dep[MAXN],pre[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].get(v,head[u],w,0);head[u]=tol++; edge[tol].get(u,head[v],rw,0);head[v]=tol++; } int sap(int start,int end,int N) { memset(gap,0,sizeof(gap)); memset(dep,0,sizeof(dep)); memcpy(cur,head,sizeof(head)); int u=start; pre[u]=-1; gap[0]=N; int ans=0; while(dep[start]<N) { if(u==end) { int Min=INF; for(int i=pre[u];i!=-1;i=pre[edge[i^1].to]) if(Min>edge[i].cap-edge[i].flow) Min=edge[i].cap-edge[i].flow; for(int i=pre[u];i!=-1;i=pre[edge[i^1].to]) { edge[i].flow+=Min; edge[i^1].flow-=Min; } u = start; ans+=Min; 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]=pre[v]=i; break; } } if(flag) { 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[pre[u]^1].to; } return ans; } void Link(int u,int v,int w) { EE->next=Graph[u].first;EE->to=v;EE->w=w;Graph[u].first=EE++; } void input() { ANS2=m; memset(E,0,sizeof(E)); memset(Graph,0,sizeof(Graph)); EE=E+1; int a,b,c; for(int i=1;i<=m;i++) { scanf("%d%d%d",&a,&b,&c); Link(a,b,c); Link(b,a,c); } } void finddist(int &s) { int ans=2000000000; for(int i=1;i<=N;i++) if(visit[i]==0) { if(dist[i]<ans) { ans=dist[i]; s=i; } } visit[s]=1; } void Dijkstra(int s) { dist[s]=0; for(int k=1;k<=N-1;k++) { finddist(s); for(EDGE *p=Graph[s].first;p;p=p->next) if(dist[s]+p->w<dist[p->to]) dist[p->to]=dist[s]+p->w; } } void CSH() { memset(visit,0,sizeof(visit)); for(int i=0;i<maxn;i++) dist[i]=1000000000; } void dfs(int s,int ans) { if(s==N) { ANS2=min(ans,ANS2); return ; } for(EDGE *p=Graph[s].first;p;p=p->next) { if(dist[s]+p->w==dist[p->to]) { if(VISIT[s]==0) { VISIT[s]=1;nn++;} if(VISIT[p->to]==0) { VISIT[p->to]=1;nn++;} addedge(s,p->to,1,0); dfs(p->to,ans+1); } } } void solve() { nn=0; memset(VISIT,0,sizeof(VISIT)); CSH(); Dijkstra(1); init(); dfs(1,0); printf("%d %d\n",sap(1,N,nn),m-ANS2); } int main() { // freopen("a.in","r",stdin); // freopen("a.out","w",stdout); while(cin>>N>>m) { input(); solve(); } }