题意:
给出一个有向图,询问最多删掉几个点,使得起点到终点的最短路大于k,起点和终点不能删。
题解:
先用Floyd处理出两两之间的最短路,然后对于每条边,如果d[1][x]+d[x][y]+d[y][n]<=k,则说明这条边是关键边。
然后拆点,对拆点后的图建立由关键边组成的网络,跑最大流即可。
需要注意的一点是,可以被删除的点,拆点边的容量是1。起点和终点不能被删除,把容量置为无限大即可。
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+100; const int inf=1e9; int n,m,k; struct node { int u,v,w,nxt; }edge[maxn<<1]; int head[maxn],tot; void addedge (int u,int v,int w) { edge[tot].u=u; edge[tot].v=v; edge[tot].w=w; edge[tot].nxt=head[u]; head[u]=tot++; edge[tot].u=v; edge[tot].v=u; edge[tot].w=0; edge[tot].nxt=head[v]; head[v]=tot++; } int dep[maxn],inq[maxn],cur[maxn],wjm,maxflow,s,t; bool bfs () { for (int i=0;i<=t;i++) { cur[i]=head[i]; dep[i]=inf; inq[i]=0; } dep[s]=0; queue<int> q; q.push(s); while (q.size()) { int u=q.front(); q.pop(); inq[u]=0; for (int i=head[u];i!=-1;i=edge[i].nxt) { int v=edge[i].v; if (dep[v]>dep[u]+1&&edge[i].w) { dep[v]=dep[u]+1; if (inq[v]==0) { q.push(v); inq[v]=1; } } } } if (dep[t]!=inf) return 1; return 0; } int dfs (int u,int flow) { int increase=0; if (u==t) { wjm=1; maxflow+=flow; return flow; } int used=0; for (int i=cur[u];i!=-1;i=edge[i].nxt) { cur[u]=i; int v=edge[i].v; if (edge[i].w&&dep[v]==dep[u]+1) { if (increase=dfs(v,min(flow-used,edge[i].w))) { used+=increase; edge[i].w-=increase; edge[i^1].w+=increase; if (used==flow) break; } } } return used; } int Dinic () { while (bfs()) { wjm=1; while (wjm==1) { wjm=0; dfs(s,inf); } } return maxflow; } pair<int,int> e[maxn]; int g[1010][1010]; int main () { while (scanf("%d%d%d",&n,&m,&k)&&n&&m&&k) { for (int i=0;i<=n;i++) for (int j=0;j<=n;j++) g[i][j]=1e6; for (int i=1;i<=m;i++) scanf("%d%d",&e[i].first,&e[i].second),g[e[i].first][e[i].second]=1; for (int i=1;i<=n;i++) g[i][i]=0; for (int k=1;k<=n;k++) for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) g[i][j]=min(g[i][j],g[i][k]+g[k][j]); s=1;t=n*2+1; for (int i=0;i<=t;i++) head[i]=-1;tot=0;wjm=0;maxflow=0; addedge(s,1,inf); for (int i=2;i<n;i++) addedge(i,i+n,1); addedge(1,1+n,inf); addedge(n,n*2,inf); for (int i=1;i<=m;i++) { int x=e[i].first; int y=e[i].second; if (g[1][x]+g[x][y]+g[y][n]<=k) { addedge(x+n,y,1); } } addedge(n*2,t,inf); printf("%d ",Dinic()); } }