http://acm.hdu.edu.cn/showproblem.php?pid=4411
3 4 2 0 1 3 0 2 4 1 3 2 2 3 2 0 0 0
14
/** hdu 4411 最小费用最大流 题目大意:给定一个图,有0~n个共n+1个顶点,从0点出发的k个警察去其余n个点抓小偷,最后还要回到0点(可以有的警察不出动),必须保证的是在抓第i个顶点 的小偷是第i-1顶点的小偷已经被抓住了,否则抓捕计划失败。问怎么样做能使所有警察走的路程最短 解题思路:很考思维的一道网络流的题,建图的难点在于抓第i个顶点的小偷的时候必须保证第i-1点的小偷已经被抓走了和警察不一定全用。对于点i分成两个点i1,i2中间用流量为1权值为-100000的边 连接,然后对i2点和j1(j>i)的点连一条流量为1,权值为ij的最短距离的边就可以了。源点到0连流量为k费用为0的点每个i1点和0之间连权值为1,费用为0i的 最短距离,每个i2点和汇点连流量为1,费用为0i最小距离的点。由于k个警察不一定全用到,那么在0和汇点之间连一条流量为k,费用为0的点。 最后最消费用加上k*10000就是答案了。 注:为什么连汇点和0之间的边,我这样理解我们每个i1和i2之间都有费用为-100000的点也就是i1和i2之间还能连的话,一定不用走0~汇点的边,这样就不会改变最小费用了 */ #include <stdio.h> #include <string.h> #include <algorithm> #include <string.h> using namespace std; const int oo=1e9; const int maxm=1111111; const int maxn=2222; int node,src,dest,edge; int head[maxn],p[maxn],dis[maxn],q[maxn],vis[maxn]; struct edgenode { int to; int flow; int cost; int next; } edges[maxm]; void prepare(int _node,int _src,int _dest); void addedge(int u,int v,int f,int c); bool spfa(); inline int min(int a,int b) { return a<b?a:b; } inline void prepare(int _node,int _src,int _dest) { node=_node; src=_src; dest=_dest; for (int i=0; i<node; i++) { head[i]=-1; vis[i]=false; } edge=0; } void addedge(int u,int v,int f,int c) { edges[edge].flow=f; edges[edge].cost=c; edges[edge].to=v; edges[edge].next=head[u]; head[u]=edge++; edges[edge].flow=0; edges[edge].cost=-c; edges[edge].to=u; edges[edge].next=head[v]; head[v]=edge++; } bool spfa() { int i,u,v,l,r=0,tmp; for (i=0; i<node; i++) dis[i]=oo; dis[q[r++]=src]=0; p[src]=p[dest]=-1; for (l=0; l!=r; ((++l>=maxn)?l=0:1)) { for (i=head[u=q[l]],vis[u]=false; i!=-1; i=edges[i].next) { if (edges[i].flow&&dis[v=edges[i].to]>(tmp=dis[u]+edges[i].cost)) { dis[v]=tmp; p[v]=i^1; if (vis[v]) continue; vis[q[r++]=v]=true; if (r>=maxn) r=0; } } } return p[dest]>=0; } int spfaflow() { int i,ret=0,delta; while (spfa()) { for (i=p[dest],delta=oo; i>=0; i=p[edges[i].to]) { delta=min(delta,edges[i^1].flow); } for (int i=p[dest]; i>=0; i=p[edges[i].to]) { edges[i].flow+=delta; edges[i^1].flow-=delta; } ret+=delta*dis[dest]; } return ret; } int n,m,k; int a[105][105]; int main() { while(~scanf("%d%d%d",&n,&m,&k)) { if(n==0&&m==0&&k==0)break; memset(a,0x3f3f3f3f,sizeof(a)); for(int i=0; i<m; i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); if(a[u][v]>w) a[u][v]=a[v][u]=w; } for(int k=0; k<=n; k++) { for(int i=0; i<=n; i++) { for(int j=0; j<=n; j++) { a[i][j]=min(a[i][j],a[i][k]+a[k][j]); } } } prepare(2*n+3,2*n+1,2*n+2); addedge(src,0,k,0); addedge(0,dest,k,0); for(int i=1;i<=n;i++) { addedge(0,i,1,a[0][i]); addedge(i,i+n,1,-100000); addedge(i+n,dest,1,a[0][i]); } for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { addedge(i+n,j,1,a[i][j]); } } printf("%d\n",spfaflow()+n*100000); } return 0; }