zoukankan      html  css  js  c++  java
  • [BZOJ 4873][SHOI&SXOI2017]寿司餐厅(最大权闭合子图)

    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想知道,在这家餐厅吃寿司,自己能获得的总美
    味度(包括所有吃掉的单种寿司的美味度和所有被累加的综合美味度)减去花费的总钱数的最大值是多少。由于她
    不会算,所以希望由你告诉她

    Solution

    最大权闭合子图

    (考试的时候没有想到这种神奇的依赖关系和建图方式)

    区间[i,j]需要向[i+1,j]和[i,j-1]连边,INF

    区间[i,i]向点i连边,INF

    每个区间如果d[i][j]为正由s向它连容量为d[i][j]的边

    为负则向t连容量为-d[i][j]的边

    每个点i向t连容量a[i]的边

    为了那个“mx^2+cx元钱”还需要每个点i向它的编号a[i]连容量为INF的边,然后每个a[i]向t连m*a[i]*a[i]的边

    ↑当时被这个条件吓到了…现在发现并不是想的那样2333

    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define INF 0x3f3f3f3f
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){
            if(c=='-')f=-1;c=getchar();
        }
        while(c>='0'&&c<='9'){
            x=x*10+c-'0';c=getchar();
        }
        return x*f;
    }
    int s,t,n,m,a[105],dot[105][105],id,key[1005];
    int head[50005],cnt=0,level[50005];
    struct Node
    {
        int next,to,cap;
    }Edges[1000005];
    void addedge(int u,int v,int c)
    {
        Edges[cnt].next=head[u];
        head[u]=cnt;
        Edges[cnt].to=v;
        Edges[cnt++].cap=c;
    }
    void insert(int u,int v,int c)
    {
        addedge(u,v,c);
        addedge(v,u,0);
    }
    queue<int>q;
    bool bfs()
    {
        memset(level,-1,sizeof(level));
        level[s]=0;q.push(s);
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(int i=head[u];~i;i=Edges[i].next)
            {
                int v=Edges[i].to;
                if(level[v]==-1&&Edges[i].cap)
                level[v]=level[u]+1,q.push(v);
            }
        }
        if(level[t]==-1)return false;
        return true;
    }
    int dfs(int u,int flow)
    {
        if(u==t)return flow;
        int f=0,d=0;
        for(int i=head[u];~i&&f<flow;i=Edges[i].next)
        {
            int v=Edges[i].to;
            if(level[v]==level[u]+1&&Edges[i].cap)
            {
                d=dfs(v,min(flow-f,Edges[i].cap));
                f+=d;
                Edges[i].cap-=d;
                Edges[i^1].cap+=d; 
            }
        }
        if(!f)level[u]=-1;
        return f;
    }
    int main()
    {
        memset(head,-1,sizeof(head));
        n=read(),m=read();
        s=0,t=n*n+2*n+1;id=n+1;
        for(int i=1;i<=n;i++)
        a[i]=read();
        int ans=0;
        for(int i=1;i<=n;i++)
        for(int j=i;j<=n;j++)
        ++id,dot[i][j]=id;
        for(int i=1;i<=n;i++)
        {
            for(int j=i;j<=n;j++)
            {
                int x=read();
                if(x>0)insert(s,dot[i][j],x),ans+=x;
                else insert(dot[i][j],t,-x);
                if(i!=j)
                {
                    insert(dot[i][j],dot[i+1][j],INF);
                    insert(dot[i][j],dot[i][j-1],INF);
                }
                else insert(dot[i][j],i,INF);
            }
            insert(i,t,a[i]);
            if(!key[a[i]])++id,key[a[i]]=id,insert(id,t,m*a[i]*a[i]);
            insert(i,key[a[i]],INF);
    
        }
        int d=0;
        while(bfs())
        {
            while(d=dfs(s,INF))
            ans-=d;
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    js 词法作用域揭秘
    Python 操作 Redis 发布订阅
    Logistic Regression
    快速逆平方根
    牛顿法
    Ubuntu安装BCC
    树莓派4b安装Ubuntu20.04
    丢弃法
    SpringBoot整合Redis
    Linear Regression
  • 原文地址:https://www.cnblogs.com/Zars19/p/6799916.html
Copyright © 2011-2022 走看看