题目描述
皮卡丘被火箭队用邪恶的计谋抢走了!这三个坏家伙还给小智留下了赤果果的挑衅!为了皮卡丘,也为了正义,小智和他的朋友们义不容辞的踏上了营救皮卡丘的道路。
火箭队一共有NN个据点,据点之间存在MM条双向道路。据点分别从11到NN标号。小智一行KK人从真新镇出发,营救被困在NN号据点的皮卡丘。为了方便起见,我们将真新镇视为00号据点,一开始KK个人都在00号点。
由于火箭队的重重布防,要想摧毁KK号据点,必须按照顺序先摧毁11到K-1K−1号据点,并且,如果K-1K−1号据点没有被摧毁,由于防御的连锁性,小智一行任何一个人进入据点KK,都会被发现,并产生严重后果。因此,在K-1K−1号据点被摧毁之前,任何人是不能够经过KK号据点的。
为了简化问题,我们忽略战斗环节,小智一行任何一个人经过KK号据点即认为KK号据点被摧毁。被摧毁的据点依然是可以被经过的。
KK个人是可以分头行动的,只要有任何一个人在K-1K−1号据点被摧毁之后,经过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 }