hdu4411--最小费用最大流

来源:互联网 发布:石家庄优化公司 编辑:程序博客网 时间:2024/05/16 09:22

A - Arrest
Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u
Submit Status

Description

There are (N+1) cities on TAT island. City 0 is where police headquarter located. The economy of other cities numbered from 1 to N ruined these years because they are all controlled by mafia. The police plan to catch all the mafia gangs in these N cities all over the year, and they want to succeed in a single mission. They figure out that every city except city 0 lives a mafia gang, and these gangs have a simple urgent message network: if the gang in city i (i>1) is captured, it will send an urgent message to the gang in city i-1 and the gang in city i -1 will get the message immediately. 
The mission must be carried out very carefully. Once a gang received an urgent message, the mission will be claimed failed. 
You are given the map of TAT island which is an undirected graph. The node on the graph represents a city, and the weighted edge represents a road between two cities(the weight means the length). Police headquarter has sent k squads to arrest all the mafia gangs in the rest N cities. When a squad passes a city, it can choose to arrest the gang in the city or to do nothing. These squads should return to city 0 after the arrest mission. 
You should ensure the mission to be successful, and then minimize the total length of these squads traveled. 
 

Input

There are multiple test cases. 
Each test case begins with a line with three integers N, M and k, here M is the number of roads among N+1 cities. Then, there are M lines. Each of these lines contains three integers X, Y, Len, which represents a Len kilometer road between city X and city Y. Those cities including city 0 are connected. 
The input is ended by “0 0 0”. 
Restrictions: 1 ≤ N ≤ 100, 1 ≤ M ≤ 4000, 1 ≤ k ≤ 25, 0 ≤ Len ≤ 1000 
 

Output

For each test case,output a single line with a single integer that represents the minimum total length of these squads traveled. 
 

Sample Input

3 4 20 1 30 2 41 3 22 3 20 0 0
 

Sample Output

14
题意:在0点事警察总部,其余1~n n个点有黑手党,总部计划去n个点把所有黑手党抓获并且再回到0点,黑手党之间有一个特殊联络方式,就是在i点的黑手党只能通知i-1点的黑手党,一旦消息被泄露计划就会失败,所以我们在抓i之前先把i-1抓了。在n个点之间有一些双向路线,路线有一个距离,总部派出k个警察去执行这项任务,每个警察到达n点之后可以等待,也可以实施抓捕。
问所有警察完成任务后并回到0点所走的最短距离是多少;
这道题是一个最小费用问题,不一定最大流,因为不一定所有警察都有必要出动,但是关键在于建立模型,怎样先抓i-1,再抓i,后来经过看大神们的博客以及自己分析画图理解总算搞明白了;
先说一说求取最小费用最大流问题,解决这个问题的方法是spfa,就是把花费(在本题中就是路径长度)作为路径长度,spfa算法是求最短距离的,最短距离不就是最小花费吗^^,然后多次spfa寻找最短路径(无限寻找增广路,直到没有,增广路是靠流量增广的,没流量了就不增了),每次记录最短路 路径,然后从终点沿最短路径返回,找到最小流量,再次从终点沿最短路径返回,把路径上的流量减掉刚刚的到的最小流量,这样每次增广,记录最大费用(达到终点的费用)记录最小流量(每次沿最短路径返回的得的最小流量),最终算出最小费用最大流量;
再回到本题中,所有边都是无向边,可以把任意点之间最短距离求出(N<=100),怎么保证按1 2 3,,,n-1,n,的顺序走呢,方法是把点扩展建立负权边,当按照最短路增广时,必然优先走负权边(-1000000,很小的边),每个点扩展后的点连接该点没扩展时的点的后面的所有点,因为警察不单是只会走到下面一个点,也可以走到后面有点的,当我们加了负权边后,寻找最短路径肯定沿着负边权走,这样1,2,3,,n-1,n,都能走到,而且不会出现先在n后走 (<n)的点,走到n以后直接回到汇点(最后加一个汇点连接所有扩展后的边),相当于回到0点,加一个源点连接0点,流量为k,花费为0,0指向汇点流量为k花费为0,当增广完负权边后就走S->0->T,这条边花费为0,增广结束,得到最小费用;
自己画一下图就会清晰了!!

#include <iostream>#include <string.h>#include <stdio.h>#include <algorithm>#include <queue>#define V 10100#define E 1000100#define inf 99999999const int ff=1000000;using namespace std;int vis[V];int dist[V];int pre[V];struct Edge{    int u,v,c,cost,next;} edge[E];int head[V],cnt;void init(){    cnt=0;    memset(head,-1,sizeof(head));}void addedge(int u,int v,int c,int cost){    edge[cnt].u=u;    edge[cnt].v=v;    edge[cnt].cost=cost;    edge[cnt].c=c;    edge[cnt].next=head[u];    head[u]=cnt++;    edge[cnt].u=v;    edge[cnt].v=u;    edge[cnt].cost=-cost;    edge[cnt].c=0;    edge[cnt].next=head[v];    head[v]=cnt++;}bool spfa(int begin,int end){    int u,v;    queue<int> q;    for(int i=0; i<=end+2; i++)    {        pre[i]=-1;        vis[i]=0;        dist[i]=inf;    }    vis[begin]=1;    dist[begin]=0;    q.push(begin);    while(!q.empty())    {        u=q.front();        q.pop();        vis[u]=0;        for(int i=head[u]; i!=-1; i=edge[i].next)        {            if(edge[i].c>0)            {                v=edge[i].v;                if(dist[v]>dist[u]+edge[i].cost)                {                    dist[v]=dist[u]+edge[i].cost;                    pre[v]=i;                    if(!vis[v])                    {                        vis[v]=true;                        q.push(v);                    }                }            }        }    }    return dist[end]!=inf;}int MCMF(int begin,int end){    int ans=0,flow;    int flow_sum=0;    while(spfa(begin,end))    {        flow=inf;        for(int i=pre[end]; i!=-1; i=pre[edge[i].u])        {            if(edge[i].c<flow)                flow=edge[i].c;        }        for(int i=pre[end]; i!=-1; i=pre[edge[i].u])        {            edge[i].c-=flow;            edge[i^1].c+=flow;        }        ans+=dist[end];        flow_sum += flow;    }    return ans;}int d[200][200];int main(){    int S,T;    int n,m,k;    int u,v,f,c;    while(scanf("%d%d%d",&n,&m,&k)!=-1)    {        if(n==0&&m==0)            break;        for(int i=0; i<=n; i++)        {            for(int j=0; j<=n; j++)                d[i][j]=(i==j)?0:inf;        }        S=n*2+1,T=n*2+2;        for(int i=0; i<m; i++)        {            scanf("%d%d%d",&u,&v,&c);            d[u][v]=d[v][u]=min(d[u][v],c);        }        for(int i=0; i<=n; i++)            for(int j=0; j<=n; j++)                for(int k=0; k<=n; k++)                    if(d[j][i]<inf&&d[i][k]<inf&&d[j][k]>d[j][i]+d[i][k])                        d[j][k]=d[j][i]+d[i][k];        init();        addedge(S,0,k,0);        addedge(0,T,k,0);        for(int i=1; i<=n; i++)        {            addedge(0,i,1,d[0][i]);            addedge(i,i+n,1,-ff);            addedge(i+n,T,1,d[0][i]);        }        for(int i=1; i<n; i++)            for(int j=i+1; j<=n; j++)                addedge(i+n,j,1,d[i][j]);///i与i后面的点全部建边        int ans=MCMF(S,T);        printf("%d\n",ans+ff*n);    }    return 0;}







1 0
原创粉丝点击