点击打开链接
题意:从0出发,1~N每个城镇有个小偷,我们要把他们全部抓到,我们可以派出k个警察,但是再抓i城镇的小偷之前,i城镇之前的所有城镇的小偷已经被抓了
思路:哪有什么思路,看了网上的题解,为了将所有的点都跑到,我们将每个点拆成两个点,之间连一条容量为1,费用为-1000000的边,为什么这么连,这是为了保证每个点的跑到的条件,因为最小费用流的增广路径是通过最短路来完成的,这样我的点拆成两个点之间的边加在最短路里肯定是会使路径更短的,这样也就保证了每个点都跑得到,现在说一说建边的方法,建立源点与0连一条容量为k费用为0的边,拆的点i与i+n连一条容量为1,费用为-1000000的边,然后0与汇点建立一条容量为k费用为0的边,这又是为什么呢,据说这些警察可以不全部出动去抓小偷,那他们就直接走这条边就好了,还有我们需要求出两点之间的最短距离,用floyd即可,然后连I到J的边,容量为1,费用为i到j的最短路(I<J),这样在增广时才能保证是从0顺次走到N,最后最小费用流+n*1000000就是结果了,将费用补回来
#include <queue> #include <vector> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <algorithm> #include <functional> using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int maxn=310; typedef pair<int,int> P; struct edge{ int to,cap,cost,rev; edge(); edge(int a,int b,int c,int d){to=a,cap=b,cost=c,rev=d;}; }; vector<edge>G[maxn]; int h[maxn],dis[maxn],prevv[maxn],preve[maxn],V; void add_edge(int st,int en,int cap,int cost){ G[st].push_back(edge(en,cap,cost,G[en].size())); G[en].push_back(edge(st,0,-cost,G[st].size()-1)); } int min_cost_flow(int st,int en,int f){ int ans=0; memset(h,0,sizeof(h)); while(f>0){ priority_queue<P,vector<P>,greater<P> >que; memset(dis,inf,sizeof(dis)); dis[st]=0;que.push(P(0,st)); while(!que.empty()){ P p=que.top();que.pop(); int v=p.second; if(dis[v]<p.first) continue; for(unsigned int i=0;i<G[v].size();i++){ edge &e=G[v][i]; if(e.cap>0&&dis[e.to]>dis[v]+e.cost+h[v]-h[e.to]){ dis[e.to]=dis[v]+e.cost+h[v]-h[e.to]; prevv[e.to]=v; preve[e.to]=i; que.push(P(dis[e.to],e.to)); } } } if(dis[en]==inf) return -1; for(int i=0;i<maxn;i++) h[i]+=dis[i]; int d=f; for(int i=en;i!=st;i=prevv[i]){ d=min(d,G[prevv[i]][preve[i]].cap); } f-=d; ans+=d*h[en]; for(int i=en;i!=st;i=prevv[i]){ edge &e=G[prevv[i]][preve[i]]; e.cap-=d; G[i][e.rev].cap+=d; } } return ans; } int num[maxn][maxn]; void floyd(){ for(int i=0;i<=V;i++){ for(int j=0;j<=V;j++){ for(int k=0;k<=V;k++) num[j][k]=min(num[j][k],num[j][i]+num[i][k]); } } } int main(){ int m,k,a,b,c; while(scanf("%d%d%d",&V,&m,&k)!=-1){ if(V==0&&m==0&&k==0) break; memset(num,inf,sizeof(num)); for(int i=0;i<maxn;i++) G[i].clear(); for(int i=0;i<m;i++){ scanf("%d%d%d",&a,&b,&c); num[a][b]=num[b][a]=min(num[a][b],c); } floyd(); add_edge(2*V+10,0,k,0);add_edge(0,2*V+11,k,0); for(int i=1;i<=V;i++){ for(int j=i+1;j<=V;j++){ add_edge(i+V,j,1,num[i][j]); } add_edge(0,i,1,num[0][i]); add_edge(i,i+V,1,-1000000); add_edge(i+V,2*V+11,1,num[0][i]); } int ans=min_cost_flow(2*V+10,2*V+11,k); printf("%d\n",ans+V*1000000); } return 0; }