zoukankan      html  css  js  c++  java
  • BZOJ_4873_[Shoi2017]寿司餐厅_最大权闭合子图

    BZOJ_4873_[Shoi2017]寿司餐厅_最大权闭合子图

    题意:http://www.lydsy.com/JudgeOnline/problem.php?id=4873

    分析:我们发现分数正负都有,并且之间有依赖关系,很容易想到最大权闭合子图。

    建图:

    1.S向正点连边,负点向T连边。

    2.选了[i~j]显然要选[i+1~j]和[i~j-1],分别连边。

    3.对于i==j的点,向对应的寿司连边。

    4.总花费m*x*x+c*x拆成两部分。对于每个代号x,向T连容量为m*x*x的边,c*x这部分我们考虑算f[i][i]时把f[i][i]的值减掉x,当然也可以每个寿司向T连容量为x的边。

    完了。

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <queue>
    using namespace std;
    #define inf 100000000
    #define LL long long
    #define S (30000)
    #define T (30001)
    int d[110][110],n,m;
    int head[31000],to[4000000],nxt[4000000],cnt=1;
    int dep[31000],a[110],tot,idx[110][110],mxn;
    LL flow[4000000],sum;
    inline void add(int u,int v,LL f)
    {
        to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;flow[cnt]=f;
        to[++cnt]=u;nxt[cnt]=head[v];head[v]=cnt;flow[cnt]=0;   
    }
    bool bfs()
    {
        queue <int> q;
        memset(dep,0,sizeof(dep));
        dep[S]=1;q.push(S);
        while(!q.empty())
        {
            int x=q.front();q.pop();
            for(int i=head[x];i;i=nxt[i])
            {
                if(!dep[to[i]]&&flow[i])
                {
                    dep[to[i]]=dep[x]+1;
                    if(to[i]==T)return 1;
                    q.push(to[i]);  
                }
            }
        }
        return 0;
    }
    LL dfs(int x,LL mf)
    {
        if(x==T)return mf;
        LL nf=0;
        for(int i=head[x];i;i=nxt[i])
        {
            if(dep[to[i]]==dep[x]+1&&flow[i])
            {
                int tmp=dfs(to[i],min(flow[i],mf-nf));
                nf+=tmp;
                flow[i]-=tmp;
                flow[i^1]+=tmp;
                if(nf==mf)break;
            }
        }
        dep[x]=0;
        return nf;
    }
    void dinic()
    {
        LL f;
        while(bfs())
        {
            while(f=dfs(S,inf))
                sum-=f; 
        }
        printf("%lld",sum);
    }
    int main()
    {
        register int i,j;
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++)
            for(j=i;j<=n;j++)
                idx[i][j]=++tot;
        for(i=1;i<=n;i++)scanf("%d",&a[i]),mxn=max(mxn,a[i]);
        for(i=1;i<=mxn;i++)add(tot+i,T,m*i*i);
        for(i=1;i<=n;i++)add(idx[i][i],tot+a[i],inf);
        for(i=1;i<=n;i++)
        {
            for(j=i;j<=n;j++)
            {
                scanf("%d",&d[i][j]);
                if(i==j)d[i][j]-=a[i];
                else{
                    add(idx[i][j],idx[i+1][j],inf);
                    add(idx[i][j],idx[i][j-1],inf); 
                }
                if(d[i][j]>0)
                {
                    sum+=d[i][j];   
                    add(S,idx[i][j],d[i][j]);
                }
                else{
                    add(idx[i][j],T,-d[i][j]);
                }
            }
        }
        dinic();
    }
    
  • 相关阅读:
    HashMap数据结构分析(jdk8)
    ConcurrentHashMap数据结构(jdk8)
    TOJ1373_多项式规律
    Windows程序基础——Windows应用程序的基本概念
    Why to learn MFC?
    TOJ1062
    TOJ1369
    TOJ1003
    vue 生命周期~~
    如何跨域访问的两种方法~
  • 原文地址:https://www.cnblogs.com/suika/p/8456939.html
Copyright © 2011-2022 走看看