HDU 4411 Arrest 费用流

来源:互联网 发布:联通网络机顶盒破解 编辑:程序博客网 时间:2024/05/21 20:24

费用流是每次找最短路然后沿着这条路增广,然后这条路因为增广了,所以就流量为0,相当于不存在了,所以可以继续找最短路,不怕出现重复,然后求的是全图的,这点切记
有n+1个城市,0市为警察局所在城市其中有k个警察,在其他n个城市中,均有小偷。有m条路,每条路有其特定路程,求k个警察将n个城市的小偷全抓捕到0市的最短路程。其中抓小偷必须从1、2、3、、、n按照城市号码严格递增顺序抓。
最小费用流的问题。样例输出解释:0->1->3(不抓小偷)->2->3->1->0。路程和为3+2+2+2+2+3=14。
设置超级源点s,超级汇点t。将0点与s和t建立容量为k,费用为0的边,并将其他n点拆掉。n个点与0点建立容量1费用为两点最短路的边,同时n个被拆出来的点与t建立容量为1费用为两点最短路的边,n个点与其被拆出来的点建立容量为1费用足够小的边(足够小的意思是保证不会出现s->0->t),跑一边最小费用,最后输出的时候把n个足够小费用加回去。

#include <iostream>#include <stdio.h>using namespace std;const int oo=1e9;const int maxm=1111111;const int maxn=220;const int ff=100000;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 a[maxn][maxn];int main(){    int n,m,k;     while(~scanf("%d%d%d",&n,&m,&k) && (n || m || k))    {        //init();       int  s=n*2+1;       int  t=s+1;        prepare(n*2+3,s,t);        //for(int i=0; i<=n; i++)         // for(int j=0; j<=n; j++)         for(int i=0; i<m; i++)            for(int j=0; j<m; j++)            if (i!=j) a[i][j]=oo;            else a[i][j]=0;        //while(m--)        for(int i=0; i<m; i++)        {            int u,v,w;            scanf("%d%d%d",&u,&v,&w);            a[u][v]=a[v][u]=min(w,a[u][v]);        }        for(int l=0;l<=n;l++)//Floyd求最短路           for(int i=0;i<=n;i++)               for(int j=0;j<=n;j++)                   if(a[i][l]<oo && a[l][j]<oo && a[i][l]+a[l][j]<a[i][j])                      a[i][j]=a[i][l]+a[l][j];        addedge(s,0,k,0);//源点与0点,容量为k,费用为0        addedge(0,t,k,0);//汇点与0点,容量为k,费用为0             for(int i=1; i<=n; i++)        {            for(int j=i+1; j<=n; j++)            {                addedge(i+n,j,1,a[i][j]);//先到i点再到j点            }            addedge(0,i,1,a[0][i]);//0点到i点,容量为1,费用为最短路            addedge(i,i+n,1,-ff);//拆点,cost值设为适当小的值,以免导致s->0->t            addedge(i+n,t,1,a[0][i]);//i点到0点,容量为1,费用为最短路        }        printf("%d\n",spfaflow()+ff*n);                }    return 0;}
0 0
原创粉丝点击