题意:一个人抓另一个人,有一个地图(无向),纯洁的Wu抓到Zhang的条件是:只有走最短路才能抓到他。纯洁Wu在1点,Zhang在n点。
问你Zhang要最少切断几条路可以使纯洁Wu抓不到他,还有一个问题就是Zhang最多切了多少条边使得纯洁Wu还有机会抓到他。
做法:首先看第一个问题,要求的就是从点1到点n,有几条没有边重复的最短路(这里不是说找完了最短路把它删掉,再找最短路,这样的话所有的可以通向终点的都可以认为是最短路,而是长度同为首次找到的起点连接到终点的路径),再来看第二个问题,其实最多可以切的路段,即保留source到sink的最短路中路段最短的路径,其它的都可以切掉。
因为留下的这个路径满足纯洁Wu抓到Zhang的条件。
实施过程:首先我们可以通过单源最短路算法求出以点1为源点的所有最短路(dijstra,spfa...),此时新建一个原图满足dis[v]=dis[u]+w[u->v]的图,此时的图里面存的路径只要它可以走到终点,那么这条路径就是可以让纯洁Wu找到Zhang。
如果就如上图所示Zhang最少要切掉2条,如果将其想象成网络流,当每一条边的容流量都是1的时候,显然有公共边的路径只能跑一次,这样在新图中运用最大流算法,求解即可。
注意:在求最短路的时候,定义一个路段数的数组L[p],即从源点走到p点,所经过的最小的路段数,一定要理解它的更新。
#include<iostream> #include<cstring> #include<cstdio> #include<queue> #define it __int64 #define inf 0x7fffffff using namespace std; const int N=2000+5; const int M=60000+5; int n,m; struct node { int v,next; int w; }e[M*2]; struct nodee { int v,next; int flow; }ne[M*2]; int head[N],cnt,nhead[N],ncnt,tiao; int s,t; void Init() { memset(head,-1,sizeof(head)); memset(nhead,-1,sizeof(nhead)); cnt=ncnt=0; } void add(int a,int b,int c) { e[cnt].v=b; e[cnt].w=c; e[cnt].next=head[a]; head[a]=cnt++; } void nadd(int a,int b,int c) { ne[ncnt].v=b; ne[ncnt].flow=c; ne[ncnt].next=nhead[a]; nhead[a]=ncnt++; ne[ncnt].v=a; ne[ncnt].flow=0; ne[ncnt].next=nhead[b]; nhead[b]=ncnt++; } void Input() { for(int i=1;i<=m;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); if(a==b) continue; add(a,b,c); add(b,a,c); } s=1;t=n; } class Dinic { public: void spfa() { queue<int>q; while(!q.empty()) q.pop(); for(int i=1;i<=n;i++) { dis[i]=inf; vis[i]=0; l[i]=inf; } dis[s]=0; l[s]=0; vis[s]=1; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i+1;i=e[i].next) { int v=e[i].v; if(dis[v]>dis[u]+e[i].w) { dis[v]=dis[u]+e[i].w; l[v]=l[u]+1; if(!vis[v]) { vis[v]=1; q.push(v); } } else if(dis[v]==dis[u]+e[i].w) { if(l[v]>l[u]+1) { l[v]=l[u]+1; if(!vis[v]) { vis[v]=1; q.push(v); } } } } } tiao=l[t]; } void build_map() { for(int i=1;i<=n;i++) { for(int j=head[i];j+1;j=e[j].next) { int v=e[j].v; if(dis[v]==dis[i]+e[j].w) { nadd(i,v,1); } } } } int spath() { queue<int>q; while(!q.empty()) q.pop(); memset(ndis,-1,sizeof(ndis)); ndis[s]=0; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=nhead[u];i+1;i=ne[i].next) { int v=ne[i].v; if(ndis[v]==-1&&ne[i].flow>0) { ndis[v]=ndis[u]+1; q.push(v); } } } return ndis[t]!=-1; } int Min(int a,int b) { if(a<b) return a; return b; } int dfs(int u,int flow) { int cost=0; if(u==t) return flow; for(int i=nhead[u];i+1;i=ne[i].next) { int v=ne[i].v; if(ndis[v]==ndis[u]+1&&ne[i].flow>0) { int min=dfs(v,Min(flow-cost,ne[i].flow)); if(min>0) { ne[i].flow-=min; ne[i^1].flow+=min; cost+=min; if(cost==flow) break; } else ndis[v]=-1; } } return cost; } int solve() { int res=0; while(spath()) { res+=dfs(s,inf); } return res; } private: it dis[N]; int vis[N],l[N],ndis[N]; }dinic; void Output() { dinic.spfa(); dinic.build_map(); printf("%d %d\n",dinic.solve(),m-tiao); } int main() { while(~scanf("%d%d",&n,&m)) { Init(); Input(); Output(); } return 0; }