hdu 4309 Seikimatsu Occult Tonneru 网络流

题意:

有三种不同类型的边,一种可以在里面放人,一种可以任意多人穿过,一种可以过一个人,如果通过了一个人之后可以选择增加花费使得可以通过无限的人数。有N个城市,要把尽可能多的人放在第一种里面,问最少需要多少花费。


思路:

可以转化为网络流模型,第一种边拆开就好,如(x,y)连成,x->u,u->T,x-y,这样就好,其他的就枚举第三种选择那些就好,(因为第三种只有12条)。


代码如下:


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
#include<vector>
using namespace std;
typedef __int64 ll;

const int maxnode=4000+5;
const int maxedge=1000000+5;
const int oo=1000000000;
struct Dinic
{
    int node,src,dest,nedge;
    int head[maxnode],point[maxedge],next[maxedge],flow[maxedge],capa[maxedge];
    int dist[maxnode],Q[maxnode],work[maxnode];
    void init(int _node,int _src,int _dest)
    {
        node=_node;
        src=_src;
        dest=_dest;
        for(int i=0; i<node; i++) head[i]=-1;
        nedge=0;
    }
    void addedge(int u,int v,int c1,int c2)
    {
        point[nedge]=v,capa[nedge]=c1,flow[nedge]=0,next[nedge]=head[u],head[u]=(nedge++);
        point[nedge]=u,capa[nedge]=c2,flow[nedge]=0,next[nedge]=head[v],head[v]=(nedge++);
    }
    bool dinic_bfs()
    {

        memset(dist,255,sizeof(dist));
        dist[src]=0;
        int sizeQ=0;
        Q[sizeQ++]=src;
        for(int cl=0; cl<sizeQ; cl++)
        {
            for(int k=Q[cl],i=head[k]; i>=0; i=next[i])
            {

                if(flow[i]<capa[i] && dist[point[i]]<0)
                {
                    dist[point[i]]=dist[k]+1;
                    Q[sizeQ++]=point[i];
                }
            }
        }
        return dist[dest]>=0;
    }
    int dinic_dfs(int x,int exp)
    {
        if(x==dest) return exp;
        for(int &i=work[x]; i>=0; i=next[i])
        {

            int v=point[i],tmp;
            if(flow[i]<capa[i] && dist[v]==dist[x]+1 && (tmp = dinic_dfs(v,min(exp,capa[i]-flow[i])))>0)
            {
                flow[i]+=tmp;
                flow[i^1]-=tmp;
                return tmp;
            }
        }
        return 0;
    }
    int dinic_flow()
    {

        int result=0;
        while(dinic_bfs())
        {
            for(int i=0; i<node; i++) work[i]=head[i];
            while(1)
            {
                int delta=dinic_dfs(src,oo);
                if(delta==0) break;
                result +=delta;
            }
        }
        return result;
    }
} Solver;

int N,m;
int num_tunnel,num_modern,num_ancient;
int num[110];
int tun[33],modern[1010],anc[33];
int ut[33],vt[33],um[1010],vm[1010],ua[33],va[33];
int res,sum_cost;

bool choose[33];


void cal()
{
    int tcost=0;
    for(int i=1; i<=num_ancient; i++)
    {
        if(choose[i])tcost+=anc[i];
    }
//printf("tcost=%d\n",tcost);
    if(tcost>=sum_cost)return;

    Solver.init(num_tunnel+N+2,0,num_tunnel+N+1);
    for(int i=1; i<=N; i++)
    {
        Solver.addedge(0,i,num[i],0);
    }

    for(int i=1; i<=num_tunnel; i++)
    {
        Solver.addedge(N+i,num_tunnel+N+1,tun[i],0);
        Solver.addedge(ut[i],N+i,oo,0);
        //Solver.addedge(vt[i],N+i,oo,0);
        Solver.addedge(ut[i],vt[i],oo,0);
    }
    for(int i=1; i<=num_modern; i++)
    {
        Solver.addedge(um[i],vm[i],oo,0);
    }
    for(int i=1; i<=num_ancient; i++)
    {
        if(choose[i])
        {
            Solver.addedge(ua[i],va[i],oo,0);
        }
        else
        {
            Solver.addedge(ua[i],va[i],1,0);
        }
    }
    int t=Solver.dinic_flow();
    if(t>=res)
    {
        sum_cost=tcost;
    }
}
void first()
{
    Solver.init(num_tunnel+N+2,0,num_tunnel+N+1);
    for(int i=1; i<=N; i++)
    {
        Solver.addedge(0,i,num[i],0);
    }
    for(int i=1; i<=num_tunnel; i++)
    {
        Solver.addedge(N+i,num_tunnel+N+1,tun[i],0);
        Solver.addedge(ut[i],N+i,oo,0);
       // Solver.addedge(vt[i],N+i,oo,0);
        Solver.addedge(ut[i],vt[i],oo,0);
    }
    for(int i=1; i<=num_modern; i++)
    {
        Solver.addedge(um[i],vm[i],oo,0);
    }
    for(int i=1; i<=num_ancient; i++)
    {
        Solver.addedge(ua[i],va[i],oo,0);
    }
    res=Solver.dinic_flow();
}

void dfs(int ind)
{
    if(ind>num_ancient)
    {
        //for(int i=1;i<=num_ancient;i++)printf("%d ",choose[i]);printf("\n");
        cal();
    }
    else
    {
        choose[ind]=false;
        dfs(ind+1);
        choose[ind]=true;
        dfs(ind+1);
        choose[ind]=false;
    }
}

int main()
{
    while(scanf("%d",&N)!=EOF)
    {
        scanf("%d",&m);
        num_tunnel=0;
        num_ancient=0;
        num_modern=0;
        sum_cost=0;
        for(int i=1; i<=N; i++)
        {
            scanf("%d",&num[i]);
        }
        for(int i=1; i<=m; i++)
        {
            int u,v,w,p;
            scanf("%d%d%d%d",&u,&v,&w,&p);
            if(p<0)
            {
                tun[++num_tunnel]=w;
                ut[num_tunnel]=u;
                vt[num_tunnel]=v;
            }
            else if(p==0)
            {
                modern[++num_modern]=w;
                um[num_modern]=u;
                vm[num_modern]=v;
            }
            else
            {
                sum_cost+=w;
                anc[++num_ancient]=w;
                ua[num_ancient]=u;
                va[num_ancient]=v;
            }
        }
        //printf("@@%d\n",sum_cost);
        first();
        if(res<=0)
        {
            printf("Poor Heaven Empire\n");
        }
        else
        {
            memset(choose,false,sizeof(choose));
            dfs(1);
            printf("%d %d\n",res,sum_cost);
        }
    }

    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断路器保护灵敏度校验整改及剩余电监测试点应用站用交系统断

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值