• [六省联考2017]寿司餐厅(网络流+最大权闭合子图)


    这是一道比较好的网络流题。

    看到这题,除了指数级别的暴力和所有a[i]相同的DP,并没有啥办法,只能有70pts。然后一眼就是网络流,考虑把区间变为点,对于(i,j),如果选了,则必须选(i+1,j)和(i,j-1),流量为inf。然后根据d[i][j]的正负性,正的就由源点连边,反之连向汇点。当且仅当i=j的区间,需要向每一个寿司连边,发现每种寿司选c次,计算c个id和1个m*id2,然后对每一种寿司连m*id2的流量,表示选了这种寿司一定会花这些钱,然后对每个寿司连流量id的边到其种类即可。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=13005;
    struct edge{int v,nxt,w;}e[N*10];
    int n,m,ecnt=1,S,T,ans,cnt,hd[N],bel[120],d[120][120],id[120][120],lv[N];
    void adde(int x,int y,int z)
    {
        e[++ecnt]=(edge){y,hd[x],z},hd[x]=ecnt;
        e[++ecnt]=(edge){x,hd[y],0},hd[y]=ecnt;
    }
    bool bfs()
    {
        queue<int>q;q.push(S);
        memset(lv,0,sizeof lv);
        lv[S]=1;
        while(!q.empty())
        {
            int u=q.front();q.pop();
            if(u==T)return 1;
            for(int i=hd[u];i;i=e[i].nxt)
            if(!lv[e[i].v]&&e[i].w)lv[e[i].v]=lv[u]+1,q.push(e[i].v);
        }
        return lv[T];
    }
    int dfs(int u,int low)
    {
        if(u==T||!low)return low;
        int sum=0;
        for(int i=hd[u];i&&low;i=e[i].nxt)
        if(lv[e[i].v]==lv[u]+1&&e[i].w)
        {
            int tmp=dfs(e[i].v,min(low,e[i].w));
            if(tmp>0)e[i].w-=tmp,e[i^1].w+=tmp,sum+=tmp,low-=tmp;
        }
        if(!sum)lv[u]=-1;
        return sum;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        T=12500;
        for(int i=1;i<=n;i++)scanf("%d",&bel[i]);
        for(int i=1;i<=n;i++)
        for(int j=i;j<=n;j++)
        scanf("%d",&d[i][j]);
        for(int i=1;i<=1000;i++)adde(n+i,T,m*i*i);
        for(int i=1;i<=n;i++)adde(i,n+bel[i],1e9),adde(i,T,bel[i]);
        cnt=n+1000;
        for(int i=1;i<=n;i++)
        for(int j=i;j<=n;j++)
        id[i][j]=++cnt;
        for(int i=1;i<=n;i++)
        {
            adde(id[i][i],i,1e9);
            if(d[i][i]>0)ans+=d[i][i],adde(S,id[i][i],d[i][i]);
            else adde(id[i][i],T,-d[i][i]);
        }
        for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
        {
            adde(id[i][j],id[i][j-1],1e9),adde(id[i][j],id[i+1][j],1e9);
            if(d[i][j]>0)ans+=d[i][j],adde(S,id[i][j],d[i][j]);
            else adde(id[i][j],T,-d[i][j]);
        }
        while(bfs())ans-=dfs(S,1e9);
        printf("%d",ans);
    }
    View Code
  • 相关阅读:
    Spring 源码学习
    Feign Client 原理和使用
    算法基础:排序算法看这一篇就够了
    Spring 源码学习2
    Spring 源码学习
    最优包裹组合-贪心算法
    @Transactional 事务的底层原理
    Mysql索引扫盲总结
    snowflake原理解析
    分布式ID总结
  • 原文地址:https://www.cnblogs.com/hfctf0210/p/11122779.html
Copyright © 2020-2023  润新知