题目大意:
一个有向图有N个点,M条边。现在要求删掉最少的点,使得不存在从1号点到N号点的长度<=K的路径(不能直接删掉1号点或N号点)。求最少删除多少点。
PS:边是有向的
思路:费用流+拆点(话说dfs貌似也能过,毕竟点那么少)
把每个点拆成两个点,a1和a2,中间连一条容量为1,费用为0的边(注意起点和终点的处理)
对于每一条数据中的有向边a-->b,连一条a2-->b1的容量为INF,费用为1的边
剩下的就是跑费用流啦~当最短路大于K停止
PS:这个算法是错的,请看这组数据
10 11 5 1 2 2 3 3 4 4 5 5 10 2 9 1 6 6 7 7 8 8 9 9 10
图:
正解应该是迭代加深搜索吧。不知道还有哪位神犇有神级的思路!
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #define N 200 5 #define M 500000 6 #define INF 100000000 7 using namespace std; 8 int head[N],next[M],len[M],w[M],to[M],cnt,n,m,k,S,T,dis[N],q[M<<4],pre[M]; 9 bool vis[N]; 10 void add(int u,int v,int c,int wp) 11 { 12 to[cnt]=v; len[cnt]=c; w[cnt]=wp; next[cnt]=head[u]; head[u]=cnt++; 13 to[cnt]=u; len[cnt]=0; w[cnt]=-wp; next[cnt]=head[v]; head[v]=cnt++; 14 } 15 void read() 16 { 17 memset(head,-1,sizeof head);cnt=0; 18 for(int i=2;i<n;i++) add(i,i+n,1,0); 19 add(1,1+n,INF,0); add(n,n+n,INF,0);//拆点 20 for(int i=1,a,b;i<=m;i++) 21 { 22 scanf("%d%d",&a,&b); 23 add(a+n,b,INF,1); 24 } 25 S=1; T=n+n; 26 } 27 bool spfa() 28 { 29 for(int i=0;i<=T;i++) dis[i]=INF; 30 int h=1,t=2,sta; 31 q[1]=S; vis[S]=true; dis[S]=0; pre[S]=-1; 32 while(h<t) 33 { 34 sta=q[h++]; 35 vis[sta]=false; 36 for(int i=head[sta];~i;i=next[i]) 37 if(len[i]>0&&dis[to[i]]>dis[sta]+w[i]) 38 { 39 dis[to[i]]=dis[sta]+w[i]; 40 pre[to[i]]=i; 41 if(!vis[to[i]]) 42 { 43 vis[to[i]]=true; 44 q[t++]=to[i]; 45 } 46 } 47 } 48 return dis[T]!=INF; 49 } 50 void go() 51 { 52 int cs=0; 53 while(spfa()) 54 { 55 if(dis[T]>k) break; 56 cs++;//printf("%d\n",cs); 57 for(int i=T,tmp;i!=S;i=to[tmp^1]) 58 { 59 //printf("%d\n",i); 60 tmp=pre[i]; 61 len[tmp]-=1; 62 len[tmp^1]+=1; 63 } 64 } 65 printf("%d\n",cs); 66 } 67 int main() 68 { 69 while(scanf("%d%d%d",&n,&m,&k),n||m||k) 70 { 71 read(); 72 go(); 73 } 74 return 0; 75 }
后记:这个才是假期最后一篇。