hdu 2485 Destroying the bus stations(費用流)
阿新 • • 發佈:2019-02-05
題意:
n個點,m條有向邊,問最少去掉幾個點使得從1到n的路徑(最短路)大於k?
思路:
這道題用費用流解,感覺好奇妙。。。
首先我們想,求費用流時,我們是每次用spfa求得最短路然後進行減流,直到找不到從匯點到源點的路徑。那麼對於這道題,當我們增廣出一條從1到n的最短路時,我們可以將其中的某個點刪去,使得這條路以及從這條路分支出來的路都使得不能從1走到n。所以我們可將點2~n進行拆點,所加的邊的容量為1,代表這條路只能走一次,費用為0,因為這條邊不需要花費,而其他邊的容量為1,費用為1。這樣,當我們跑費用流時,當dis【t】>k時,所流過的流量就是答案。
#include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> #include<queue> using namespace std; #define inf 0x3f3f3f3f #define maxn 200 #define maxm 4050 int head[maxn]; int dis[maxn]; int pre[maxn]; int vis[maxn]; int tot; int n,m,k; struct Edge { int to; int cost; int flow; int next; } edge[maxm*2]; void addedge(int u,int v,int w,int f) { edge[tot].to=v; edge[tot].cost=w; edge[tot].flow=f; edge[tot].next=head[u]; head[u]=tot++; edge[tot].to=u; edge[tot].cost=0-w; edge[tot].flow=0; edge[tot].next=head[v]; head[v]=tot++; return; } bool spfa(int s,int t) { memset(dis,inf,sizeof(dis)); memset(pre,-1,sizeof(pre)); memset(vis,0,sizeof(vis)); queue<int>Q; Q.push(s); dis[s]=0; vis[s]=1; int top; while(!Q.empty()) { top=Q.front(); Q.pop(); vis[top]=0; for(int i=head[top]; i!=-1; i=edge[i].next) { if(edge[i].flow>0&&dis[edge[i].to]>dis[top]+edge[i].cost) { dis[edge[i].to]=dis[top]+edge[i].cost; pre[edge[i].to]=i; if(!vis[edge[i].to]) { vis[edge[i].to]=1; Q.push(edge[i].to); } } } } if(dis[t]>0)return true; return false; } int solve(int s,int t) { int flow=0; while(spfa(s,t)) { //cout<<"++"<<endl; if(dis[t]>k)break; flow++; for(int i=pre[t]; i!=-1; i=pre[edge[i^1].to]) { edge[i].flow-=1; edge[i^1].flow+=1; } } return flow; } int main() { while(~scanf("%d%d%d",&n,&m,&k)) { if(n==0&&m==0&&k==0)break; tot=0; memset(head,-1,sizeof(head)); for(int i=2; i<n; i++) { addedge(i,i+n,0,1); } int a,b; for(int i=1; i<=m; i++) { scanf("%d%d",&a,&b); if(a!=1)a+=n; addedge(a,b,1,1); } printf("%d\n",solve(1,n)); } }