PKU 3921-Destroying the bus stations

6/15のICPC練習会で出た問題

問題概要

N個の頂点を持つ有向グラフが与えられる.
頂点1から頂点Nに向かう長さがK以下のルートを全て無くすには何個頂点を消せば良いか

解法

K以内に行ける辺を全てリストアップし,そのグラフ上で最大流を行なう.
頂点消去なので頂点の流量を1にする.

実装(C++)

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <climits>
#include <cctype>
#include <ctime>
#include <cassert>
#include <cwchar>
#include <cstdarg>
#include <cwctype>
#include <queue>
#include <stack>
#include <algorithm>
#include <list>
#include <vector>
#include <set>
#include <map>
#include <iostream>
#include <deque>
#include <complex>
#include <string>
#include <functional>
#include <iomanip>
#include <sstream>
#include <bitset>
#include <valarray>
#include <fstream>
using namespace std;

typedef int lli;
typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned long long ull;

#define REP(i,x) for(int i=0;i<(int)(x);i++)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();i++)
#define RREP(i,x) for(int i=(x);i>=0;i--)
#define RFOR(i,c) for(__typeof((c).rbegin())i=(c).rbegin();i!=(c).rend();i++)
const lli INF=1LL<<28;
lli dx[4]={-1,0,1,0},dy[4]={0,-1,0,1};
const lli MAX_V=250;
struct edge{lli to,cap,rev;};
int V;
vector<edge> G[MAX_V];
bool used[MAX_V];

void add_edge(lli from,lli to,lli cap){
	G[from].push_back((edge){to,cap,G[to].size()});
	G[to].push_back((edge){from,0,G[from].size()-1});
}

lli dfs(lli v,lli t,lli f){
	if(v==t)return f;
	used[v]=true;
	for(lli i=0;i<(lli)G[v].size();i++){
		edge &e=G[v][i];
		if(!used[e.to]&&e.cap>0){
			lli d=dfs(e.to,t,min(f,e.cap));
			if(d>0){
				e.cap-=d;
				G[e.to][e.rev].cap+=d;
				return d;
			}
		}
	}
	return 0;
}
lli max_flow(lli s,lli t){
	lli flow=0;
	for(;;){
		memset(used,0,sizeof(used));
		lli f=dfs(s,t,INF);
		if(f==0)return flow;
		flow+=f;
	}
}
int n,m,K;
int main(){
	for(;cin>>n>>m>>K;){
		if(n==0&&m==0&&K==0)break;
		int V[50][50],dist[50][50];
		REP(i,n)REP(j,n)V[i][j]=INF;
		for(int i=0;i<m;i++){
			int s,f;
			cin>>s>>f;
			s--;f--;
			V[s][f]=1;
		}
		REP(i,n)V[i][i]=0;
		REP(i,n)REP(j,n){
			dist[i][j]=V[i][j];
		}
		REP(k,n)REP(i,n)REP(j,n){
			V[i][j]=min(V[i][j],V[i][k]+V[k][j]);
		}
		for(int i=0;i<2*n;i++){
			G[i].clear();
		}
		REP(i,n)REP(j,n){
			if(V[0][i]+1+V[j][n-1]<=K&&dist[i][j]==1){
				add_edge(i*2+1,j*2,INF);
			}
		}
		REP(i,n){
			if(i==0||i==n-1){
				add_edge(i*2,i*2+1,INF);
			}else{
				add_edge(i*2,i*2+1,1);
			}
		}
		cout<<max_flow(0,n*2-1)<<endl;
	}
	return 0;
}