[费用流][floyd] Luogu P4542 营救比卡丘

题目描述

皮卡丘被火箭队用邪恶的计谋抢走了!这三个坏家伙还给小智留下了赤果果的挑衅!为了皮卡丘,也为了正义,小智和他的朋友们义不容辞的踏上了营救皮卡丘的道路。

火箭队一共有NN个据点,据点之间存在MM条双向道路。据点分别从11到NN标号。小智一行KK人从真新镇出发,营救被困在NN号据点的皮卡丘。为了方便起见,我们将真新镇视为00号据点,一开始KK个人都在00号点。

由于火箭队的重重布防,要想摧毁KK号据点,必须按照顺序先摧毁11到K-1K1号据点,并且,如果K-1K1号据点没有被摧毁,由于防御的连锁性,小智一行任何一个人进入据点KK,都会被发现,并产生严重后果。因此,在K-1K1号据点被摧毁之前,任何人是不能够经过KK号据点的。

为了简化问题,我们忽略战斗环节,小智一行任何一个人经过KK号据点即认为KK号据点被摧毁。被摧毁的据点依然是可以被经过的。

KK个人是可以分头行动的,只要有任何一个人在K-1K1号据点被摧毁之后,经过KK号据点,KK号据点就被摧毁了。显然的,只要NN号据点被摧毁,皮卡丘就得救了。

野外的道路是不安全的,因此小智一行希望在摧毁NN号据点救出皮卡丘的同时,使得KK个人所经过的道路的长度总和最少。

请你帮助小智设计一个最佳的营救方案吧!

 

 

题解

  • 因为路径之间两两不能相交,所以每个点至少且至多要被进入一次,除n以外的点做多出去一次
  • 那么我们可以把一个点拆成两个,一个入点一个出点,1-n的出点向汇点连边,源点向1到n-1的出点连边,然后源点向0连流量为k的边

代码

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <queue>
 5 #define inf 0x3f3f3f3f
 6 using namespace std; 
 7 const int N=160;
 8 int n,m,k,cnt,s,t,head[N*2],dis[N*2],f[N][N],vis[N*2],pre[N*2],ans;
 9 struct edge{int from,to,c,w,next;}e[N*N*20];
10 queue<int> Q;
11 void insert(int u,int v,int c,int w)
12 {
13     e[++cnt].from=u,e[cnt].to=v,e[cnt].c=c,e[cnt].w=w,e[cnt].next=head[u],head[u]=cnt;
14     e[++cnt].from=v,e[cnt].to=u,e[cnt].c=0,e[cnt].w=-w,e[cnt].next=head[v],head[v]=cnt;
15 }
16 bool spfa()
17 {
18     for (int i=0;i<=t;i++) dis[i]=inf;
19     Q.push(s),dis[s]=0,vis[s]=1;
20     while (!Q.empty())
21     {
22         int u=Q.front();Q.pop();
23         for (int i=head[u];i;i=e[i].next)
24             if (e[i].c&&dis[u]+e[i].w<dis[e[i].to])
25             {
26                 dis[e[i].to]=dis[u]+e[i].w,pre[e[i].to]=i;
27                 if (!vis[e[i].to]) vis[e[i].to]=1,Q.push(e[i].to);
28             }
29         vis[u]=0;
30     }
31     return dis[t]!=inf;
32 }
33 void mcf()
34 {
35     ans+=dis[t]; int x=t;
36     while (pre[x]) e[pre[x]].c--,e[pre[x]^1].c++,x=e[pre[x]].from;
37 }
38 int main()
39 {
40     scanf("%d%d%d",&n,&m,&k);
41     s=n*2+1,t=n*2+2,cnt=1,insert(s,0,k,0);
42     for (int i=1;i<=n;i++) insert(i,t,1,0);
43     for (int i=1;i<n;i++) insert(s,i+n,1,0);
44     memset(f,inf,sizeof(f));
45     for (int i=0;i<=n;i++) f[i][i]=0;
46     for (int i=1,x,y,z;i<=m;i++) scanf("%d%d%d",&x,&y,&z),f[x][y]=f[y][x]=min(f[x][y],z);
47     for (int k=0;k<=n;k++) for (int i=0;i<=n;i++) for (int j=0;j<=n;j++) if (k<i||k<j) f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
48     for (int i=0;i<n;i++) for (int j=i+1;j<=n;j++) if (f[i][j]<inf) insert(i?i+n:i,j,1,f[i][j]);
49     while (spfa()) mcf(); printf("%d",ans);
50 }

 

posted @ 2019-07-23 18:09  BEYang_Z  阅读(125)  评论(0编辑  收藏  举报