zoukankan      html  css  js  c++  java
  • hdu 5383 Yu-Gi-Oh! (费用流)

    前言

    最小费用最大流是指:满足最大流的情况下,让费用最小。
    最小费用流:仅要求费用最小,通常情况下有费用为负的边权(如果费用全为正,那么可以让流量为0,费用也就是0),可以使用最小费用最大流的算法求解,只不过终止条件变为“从原点到汇点的费用为正”
    最小费用最大流算法的原本终止条件为“从原点到汇点的容量为0”

    题目链接

    http://acm.hdu.edu.cn/showproblem.php?pid=5383

    思路

    设置超级源点S,超级汇点T
    S向0集怪兽建边,容量为1,费用为怪兽战斗力;
    1集怪兽向T建边,容量为1,费用为怪兽战斗力;
    0集怪兽向1集怪兽建边,容量为1,费用为合成怪兽最大战斗力-两个怪兽战斗力之和(前提是正数);
    S向1集怪兽建边,容量为1,费用为0,表示该怪兽不与0集任何怪兽结合;
    0集怪兽向T建边,容量为1,费用为0,表示该怪兽不与1集任何怪兽结合。
    然后跑最大费用流,注意这里不用最大流,从原点到汇点的费用为负就停止。

    #include<bits/stdc++.h>
    using namespace std;
    const int inf = 0x3f3f3f3f;
    const int N = 350;
    const int M = 2e5+10;
    struct edge
    {
        int to,val,cos,next;
    }e[M];
    int head[N],tot=-1;
    int pre[N],dis[N],path[N];
    bool vis[N];
    struct node
    {
        int op,lev,atk;
    }q[N];
    int ma[N][N];
    int n,m;
    void init()
    {
        memset(head,-1,sizeof(head)),tot=-1;
        memset(ma,0,sizeof(ma));
        memset(path,0,sizeof(path));
    }
    void add(int u,int v,int w,int c)
    {
        e[++tot].to=v,e[tot].val=w,e[tot].cos=c;
        e[tot].next=head[u],head[u]=tot;
    
        e[++tot].to=u,e[tot].val=0,e[tot].cos=-c;
        e[tot].next=head[v],head[v]=tot;
    }
    bool spfa(int s,int t)
    {
        memset(pre,-1,sizeof(pre));
        memset(dis,-inf,sizeof(dis));
        memset(vis,false,sizeof(vis));
        queue<int>q;
        dis[s]=0;
        vis[s]=true;
        q.push(s);
        while(!q.empty())
        {
            int u=q.front();q.pop();
            vis[u]=false;
            for(int i=head[u];i!=-1;i=e[i].next)
            {
                int v=e[i].to;
                if(e[i].val>0&&dis[u]+e[i].cos>dis[v])
                {
                    dis[v]=dis[u]+e[i].cos;
                    pre[v]=u;
                    path[v]=i;
                    if(!vis[v])
                    {
                        vis[v]=true;
                        q.push(v);
                    }
                }
            }
        }
        if(pre[t]==-1)return false;
        return true;
    }
    int mcmf(int s,int t)
    {
        int cost=0,flow=0;
        while(spfa(s,t))
        {
            if(dis[t]<0)break;  ///!!!!不需要满流,从原点到汇点的费用为负就停止
            int f=inf;
            for(int i=t;i!=s;i=pre[i])
                f=min(e[path[i]].val,f);
            flow+=f;
            cost+=f*dis[t];
            for(int i=t;i!=s;i=pre[i])
            {
                e[path[i]].val-=f;
                e[path[i]^1].val+=f;
            }
        }
        return cost;
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            init();
            scanf("%d%d",&n,&m);
            int s=0,t=n+1;
            for(int i=1;i<=n;i++)
            {
                scanf("%d%d%d",&q[i].op,&q[i].lev,&q[i].atk);
                if(q[i].op==0)add(s,i,1,q[i].atk),add(i,t,1,0);
                else add(i,t,1,q[i].atk),add(s,i,1,0);
            }
            int lev,atk,limit,a,b;
            for(int i=1;i<=m;i++)
            {
                scanf("%d%d%d",&lev,&atk,&limit);
                if(limit==0)
                {
                    for(int j=1;j<=n;j++)
                        for(int k=1;k<=n;k++)
                        {
                            if(j==k)continue;
                            if(q[j].op==q[k].op||q[j].lev+q[k].lev!=lev)continue;
                            if(q[j].op==0)ma[j][k]=max(ma[j][k],atk);
                            else ma[k][j]=max(ma[k][j],atk);
                        }
                }
                else if(limit==1)
                {
                    scanf("%d",&a);
                    for(int j=1;j<=n;j++)
                    {
                        if(j==a)continue;
                        if(q[a].op==q[j].op||q[a].lev+q[j].lev!=lev)continue;
                        if(q[a].op==0)ma[a][j]=max(ma[a][j],atk);
                        else ma[j][a]=max(ma[j][a],atk);
                    }
                }
                else
                {
                    scanf("%d%d",&a,&b);
                    if(q[a].op==q[b].op||q[a].lev+q[b].lev!=lev)continue;
                    if(q[a].op==0)ma[a][b]=max(ma[a][b],atk);
                    else ma[b][a]=max(ma[b][a],atk);
                }
            }
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    if(ma[i][j]>q[i].atk+q[j].atk)
                        add(i,j,1,ma[i][j]-q[i].atk-q[j].atk);
            printf("%d
    ",mcmf(s,t));
        }
    }
    
  • 相关阅读:
    Atitit 数据库view视图使用推荐规范与最佳实践与方法
    Atitit mybatis快速开发 的sql api接口
    一个数据包经过路由器和交换机各会发生什么变化
    c preprocessor
    A database of opensource HTTP proxies written in python.
    google chrome os下载
    一道笔试题多字串查找
    一个老题:将正整数n分为若干num个不同的正整数之和
    web dev framework
    memory leakage
  • 原文地址:https://www.cnblogs.com/HooYing/p/12651341.html
Copyright © 2011-2022 走看看