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

    4873: [Shoi2017]寿司餐厅

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 369  Solved: 256
    [Submit][Status][Discuss]

    Description

    Kiana最近喜欢到一家非常美味的寿司餐厅用餐。每天晚上,这家餐厅都会按顺序提供n种寿司,第i种寿司有一个
    代号ai和美味度di,i,不同种类的寿司有可能使用相同的代号。每种寿司的份数都是无限的,Kiana也可以无限次
    取寿司来吃,但每种寿司每次只能取一份,且每次取走的寿司必须是按餐厅提供寿司的顺序连续的一段,即Kiana
    可以一次取走第1,2种寿司各一份,也可以一次取走第2,3种寿司各一份,但不可以一次取走第1,3种寿司。由于餐
    厅提供的寿司种类繁多,而不同种类的寿司之间相互会有影响:三文鱼寿司和鱿鱼寿司一起吃或许会很棒,但和水
    果寿司一起吃就可能会肚子痛。因此,Kiana定义了一个综合美味度di,j(i<j),表示在一次取的寿司中,如果包含
    了餐厅提供的从第i份到第j份的所有寿司,吃掉这次取的所有寿司后将获得的额外美味度。由于取寿司需要花费一
    些时间,所以我们认为分两次取来的寿司之间相互不会影响。注意在吃一次取的寿司时,不止一个综合美味度会被
    累加,比如若Kiana一次取走了第1,2,3种寿司各一份,除了d1,3以外,d1,2,d2,3也会被累加进总美味度中。神奇
    的是,Kiana的美食评判标准是有记忆性的,无论是单种寿司的美味度,还是多种寿司组合起来的综合美味度,在
    计入Kiana的总美味度时都只会被累加一次。比如,若Kiana某一次取走了第1,2种寿司各一份,另一次取走了第2,3
    种寿司各一份,那么这两次取寿司的总美味度为d1,1+d2,2+d3,3+d1,2+d2,3,其中d2,2只会计算一次。奇怪的是,
    这家寿司餐厅的收费标准很不同寻常。具体来说,如果Kiana一共吃过了c(c>0)种代号为x的寿司,则她需要为这些
    寿司付出mx^2+cx元钱,其中m是餐厅给出的一个常数。现在Kiana想知道,在这家餐厅吃寿司,自己能获得的总美
    味度(包括所有吃掉的单种寿司的美味度和所有被累加的综合美味度)减去花费的总钱数的最大值是多少。由于她
    不会算,所以希望由你告诉她

    Input

    第一行包含两个正整数n,m,分别表示这家餐厅提供的寿司总数和计算寿司价格中使用的常数。
    第二行包含n个正整数,其中第k个数ak表示第k份寿司的代号。
    接下来n行,第i行包含n-i+1个整数,其中第j个数di,i+j-1表示吃掉寿司能
    获得的相应的美味度,具体含义见问题描述。
    N<=100,Ai<=1000

    Output

    输出共一行包含一个正整数,表示Kiana能获得的总美味度减去花费的总钱数的最大值。

    Sample Input

    3 1
    2 3 2
    5 -10 15
    -10 15
    15

    Sample Output

    12

    题解

    首先这道题我们可以发现,当我们选择了区间[L,R]时,区间[L+1,R]和[L,R-1]也被选择

    这样我们就发现,这题其实是在求最大权闭合子图

    于是我们对于[L,R](L!=R)向[L+1,R]和[L,R-1]连边

    对于[L,R](L==R),我们连边的权值为收益-a[L]

    再对每种收益连好边,具体连边请看代码

    代码

    //by 减维
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<bitset>
    #include<set>
    #include<cmath>
    #include<vector>
    #include<set>
    #include<map>
    #include<ctime>
    #include<algorithm>
    #define ll long long
    #define il inline
    #define rg register
    #define db double
    #define inf 1<<30
    #define maxn 11005
    #define eps 1e-8
    using namespace std;
    
    inline int read()
    {
        int ret=0;bool fla=0;char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-'){fla=1;ch=getchar();}
        while(ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();}
        return fla?-ret:ret;
    }
    
    struct edge{
        int to,ne,cap;
    }e[maxn<<7];
    
    int n,m,s,t,tot,ans,ecnt=1,a[105],num[105][105],val[105][105],head[maxn],layer[maxn],cur[maxn];
    
    void add(int x,int y,int z)
    {
        e[++ecnt]=(edge){y,head[x],z};head[x]=ecnt;
        e[++ecnt]=(edge){x,head[y],0};head[y]=ecnt;
    }
    
    bool bfs()
    {
        memset(layer,0,sizeof layer);layer[s]=1;
        queue<int>q;q.push(s);
        while(!q.empty())
        {
            int d=q.front();q.pop();
            for(int i=head[d];i;i=e[i].ne)
            {
                int dd=e[i].to;
                if(e[i].cap&&!layer[dd])
                {
                    layer[dd]=layer[d]+1;
                    if(dd==t) return 1;
                    q.push(dd);
                }
            }
        }
        return 0;
    }
    
    int dfs(int x,int cap)
    {
        if(x==t) return cap;
        int tmp,ret=0;
        for(int &i=cur[x];i;i=e[i].ne)
        {
            int dd=e[i].to;
            if(e[i].cap&&layer[dd]==layer[x]+1)
            {
                tmp=dfs(dd,min(cap,e[i].cap));
                ret+=tmp;cap-=tmp;
                e[i].cap-=tmp;e[i^1].cap+=tmp;
                if(cap==0) return ret;
            }
        }
        if(!ret) layer[x]=0;
        return ret;
    }
    
    void dinic()
    {
        while(bfs())
        {
            for(int i=s;i<=tot;++i) cur[i]=head[i];
            ans-=dfs(s,inf);
        }
    }
    
    int main()
    {
        n=read(),m=read();
        for(int i=1;i<=n;++i) a[i]=read();
        s=0,t=1001,tot=1001;
        for(int i=1;i<=1000;++i)
            add(i,t,m*i*i);
        for(int i=1;i<=n;++i)
            for(int j=i;j<=n;++j)
                num[i][j]=++tot,val[i][j]=read();
        for(int i=1;i<=n;++i)
            for(int j=i;j<=n;++j)
            {
                int x=val[i][j];
                if(j==i) x-=a[i],add(num[i][j],a[i],inf);
                if(x>0) add(s,num[i][j],x),ans+=x;
                else add(num[i][j],t,-x);
                if(j!=1) add(num[i][j],num[i][j-1],inf),add(num[i][j],num[i+1][j],inf);
            }
        dinic();
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    Python基础之内存管理与垃圾回收机制
    Git常用命令
    Git分支操作
    码云配置SSH公钥
    Git基本操作
    Git基本理论
    版本控制
    Python基础之Python语法
    成为一名JAVA高级工程师你需要学什么【转】
    一个java高级工程师的进阶之路【转】
  • 原文地址:https://www.cnblogs.com/rir1715/p/8243116.html
Copyright © 2011-2022 走看看