多校第一场:hdu4309(最大流+枚举)

来源:互联网 发布:c语言死机代码 编辑:程序博客网 时间:2024/06/06 09:29

                题意: n个点,每个点有初始的值 ,三种 通道,1、隧道:可以用来躲避,有固定的容量,也可以用来传递。2、普通的道路,可以无限的通过。3、桥:不花费的话能通过一人,修之后可以无限通过。问最少花费最大可以隐藏人数。       可以建立最大流模型来求解,增加一个源点S,和一个汇点T。S向每个有人的点,连一条容量为人数的边,图中普通的u->v的有向边,连一条u->v的流量为无穷的边,桥的流量则为1。对于隧道,每个隧道可以虚拟出一个点,如u->v的隧道,可以虚拟一个点x,连接u->x,x->v的流量无穷的边,和x->T的流量为隧道人数上限的边,求解最大流即可得到最大人数。       现在考虑桥的问题,题目中说明了桥最多只有12座,故可以2^12枚举修复哪些桥,不修复的桥没有花费,连接的边流量为1,要修复的桥则计算花费,边的流量为无穷,这样进行2^12次最大流就可以得到最优解。      for(int i=0;i<(1<<sum);i++)可以枚举出所有的情况。      if(i&(1<<p[i]))表示枚举该桥修复。#include<cstdio>#include<queue>#include<cstring>#include<iostream>#include<algorithm>#include<cstring>#include<map>#include<string>#include <stdio.h>#include <iostream>#include <string.h>#include<queue>#include<cmath>using namespace std;const int inf=1<<30;const int M=500,ME=3009;const int INF=0x3f3fffff;//******************************最小费用最大流模版(可以单独用来求最大流,输入的时候,cost=0就可以:适用于u->v,只要符合了流量限制,只要通过了就花费,还有一种是:u->v,每单位的流量必须花费对少费用(poj2159模板))int Head[M],Next[ME],Num[ME],Flow[ME],Cap[ME],Cost[ME],vis[ME],Q[M],InQ[M],Len[M],pre_edge[M];int top;    void clear()    {        memset(Head,-1,sizeof(Head));        memset(Flow,0,sizeof(Flow));        memset(vis,0,sizeof(vis));        top=0;    }    void addedge(int u,int v,int cap,int cost)    {        Next[top] = Head[u];        Num[top] = v;        Cap[top] = cap;        Cost[top] = cost;        Head[u] = top++;        Next[top] = Head[v];        Num[top] = u;        Cap[top] = 0;        Cost[top] = -cost;        Head[v] = top++;    }    bool SPFA(int s,int t)    {        fill(Len,Len+M,INF);        Len[s]=0;        int head = -1,tail = -1,cur;        Q[++head] = s;        while(head != tail)        {            ++tail;            if(tail >= M) tail = 0 ;            cur = Q[tail];            for(int i = Head[cur];i != -1;i = Next[i])            {                if(Cap[i]>Flow[i] && Len[Num[i]] > Len[cur] + Cost[i])                {                    Len[Num[i]] = Len[cur] + Cost[i];                    pre_edge[Num[i]] = i;                    if(!InQ[Num[i]])                    {                        InQ[Num[i]]=true;                        ++head;                        if(head >= M) head = 0;                        Q[head] = Num[i];                    }                }            }            InQ[cur]=false;        }        return Len[t] != INF;    }    int solve(int s,int t)    {       int  ans= 0;        while(SPFA(s,t))        {            int cur = t,minflow = INF;            while(cur != s)            {                if(minflow > Cap[pre_edge[cur]]-Flow[pre_edge[cur]])                    minflow = Cap[pre_edge[cur]]-Flow[pre_edge[cur]];                cur = Num[pre_edge[cur] ^ 1];            }            cur = t ;            ans+=minflow;            while(cur != s)            {                Flow[pre_edge[cur]] += minflow;                Flow[pre_edge[cur] ^ 1] -= minflow;                vis[pre_edge[cur]]=1;                cur = Num[pre_edge[cur] ^ 1];            }        }        return ans;//最大流
         int cost;//最小费用        for(int i=0;i<top;i++) //适用于u->v,只要符合了流量限制,只要通过了就花费,不管通过多少流量        {                if(Flow[i]>0)               cost+=Cost[i];        }    }//****************************************************************int n,m;int val[M];int u[1509],v[1509],w[1509],p[1509];int uu[15],vv[15],ww[15];int main(){  while(scanf("%d%d",&n,&m)!=EOF)  {      clear();      int start=0;      int end=n+25;      int b=n+1;      int k=0;      for(int i=1;i<=n;i++)      {         scanf("%d",&val[i]);         addedge(start,i,val[i],0);      }      for(int j=1;j<=m;j++)      {        scanf("%d%d%d%d",&u[j],&v[j],&w[j],&p[j]);        if(p[j]==0)        {          addedge(u[j],v[j],inf,0);        }        else if(p[j]<0)        {          addedge(u[j],b,inf,0);          addedge(b,v[j],inf,0);          addedge(b++,end,w[j],0);        }        else        {          addedge(u[j],v[j],inf,0);          uu[k]=u[j];          vv[k]=v[j];          ww[k]=w[j];          k++;          p[k]=k;        }      }      int an=solve(start,end);      int mm=1<<k;      int co=inf;          for(int i=0;i<mm;i++)     {        clear();        b=n+1;        for(int j=1;j<=n;j++)        {         addedge(start,j,val[j],0);        }       for(int j=1;j<=m;j++)       {        if(p[j]==0)        {          addedge(u[j],v[j],inf,0);        }        else if(p[j]<0)        {          addedge(u[j],b,inf,0);          addedge(b,v[j],inf,0);          addedge(b++,end,w[j],0);        }        else        {          addedge(u[j],v[j],1,0);          if((1<<(p[j]-1))&i)          addedge(u[j],v[j],inf,0);        }       }       int tmp=solve(start,end);       if(tmp==an)       {           int r=0;           for(int t=0;t<k;t++)           {             if(i&(1<<t))             r+=ww[t];           }           if(r<co)           co=r;       }      }        if(an==0)        puts("Poor Heaven Empire");        else        printf("%d %d\n",an,co);  }  return 0;}


原创粉丝点击