洛谷 P3749 [六省联考 2017] 寿司餐厅 分析

最大权闭合子图 的模型

模型:有若干个物品,每种物品有一个价值 $v_i$,选取了物品就意味着获得了价值。

物品之间有限制关系:$x \to y$ 表示若要选择物品 $x$ 则必须选择物品 $y$。目标是最大化价值和。

解法

考虑使用最小割解决此类问题:

将每个物品与源点 $s$ 和汇点 $t$ 相连。若割掉与 $s$ 相连的边表示不选这个物品,割掉与 $t$ 相连的边表示选择这个物品。

对于一个物品的价值 $v$,如果 $v>0$ 则令它与 $s$ 相连的边的权值为 $v$,与 $t$ 相连的边的权值为 $0$,将 $v$ 加入答案。表示不选择这个物品会付出 $v$ 的代价;如果 $v<0$ 则令它与 $s$ 相连的边的权值为 $0$,与 $t$ 相连的边的权值为 $-v$,表示选择这个物品会付出 $-v$ 的代价。

对于 $x \to y$ 的关系,转化为 $x$ 向 $y$ 连一条权值极大的边,显然这条边永远不会被割,如果选择了 $x$,即割掉 $x$ 与 $t$ 相连的边,那么如果不选 $y$,即割掉 $y$ 与 $s$ 相连的边,就会出现路径 $s \to x \to y \to t$,所以必须选择 $y$。而如果不选 $x$ 则对 $y$ 的选择没有影响。

至此,问题符合使用 Dinic 算法解决网络流的条件,结合最大流-最小割定理,可以使用 Dinic 算法解决此类问题。

转化

在本题中,吃了每种类型为 $x$ 的寿司需要付出 $x$ 的代价,而吃过类型为 $x$ 的寿司需要付出 $mx^2$ 的代价。考虑将每种 $d_{i,j}$ 的收益看成物品,显然如果选择 $d_{i,j}$($i<j$),则必须选择 $d_{i,j-1}$ 以及 $d_{i+1,j}$。

至此,转化完成,可以用最大权闭合子图的模型求解。

namespace LZX
{
    using namespace std;
    typedef long long i64;
    const int MAXN=6060,MAXM=16060;
    const i64 INF=0x7fffffffffffffff;
    int s,t,cnt=1,head[MAXN],to[MAXM<<1],nxt[MAXM<<1],pre[MAXN],dep[MAXN],d[105][105],id[105][105],a[105];
    i64 f[MAXM<<1];
    void g_flow_add(int a,int b,i64 c)
    {
        nxt[++cnt]=head[a];
        head[a]=cnt;
        to[cnt]=b;
        f[cnt]=c;
        nxt[++cnt]=head[b];
        head[b]=cnt;
        to[cnt]=a;
        f[cnt]=0;
    }
    bool g_flow_BFS()
    {
        int u,v;
        queue<int> q;
        memset(dep,0,sizeof(dep));
        dep[s]=1;
        q.push(s);
        do
        {
            u=q.front();
            q.pop();
            for(int i=head[u];i;i=nxt[i])
            {
                v=to[i];
                if(f[i]&&!dep[v])
                {
                    dep[v]=dep[u]+1;
                    q.push(v);
                }
            }
        }
        while(!q.empty());
        return dep[t];
    }
    i64 g_flow_DFS(int u,i64 flow)
    {
        i64 res,v,temp;
        if(u==t)
        {
            return flow;
        }
        res=0;
        for(int &i=pre[u];i;i=nxt[i])
        {
            v=to[i];
            if(f[i]&&dep[v]==dep[u]+1)
            {
                temp=g_flow_DFS(v,min(flow,f[i]));
                f[i]-=temp;
                f[i^1]+=temp;
                flow-=temp;
                res+=temp;
                if(!flow)
                {
                    break;
                }
            }
        }
        return res;
    }
    i64 g_flow_dinic()
    {
        i64 res=0;
        while(g_flow_BFS())
        {
            memmove(pre,head,sizeof(head));
            res+=g_flow_DFS(s,INF);
        }
        return res;
    }
    int _main()
    {
        int n,m,k,maxa,cost;
        i64 ans=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",a+i);
            maxa=max(maxa,a[i]);
        }
        s=1;
        t=2;
        k=2;
        for(int i=1;i<=n;i++)
        {
            for(int j=i;j<=n;j++)
            {
                scanf("%d",&d[i][j]);
                id[i][j]=++k;
            }
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=i;j<=n;j++)
            {
                cost=d[i][j];
                if(i==j)
                {
                    if(m)
                    {
                        g_flow_add(id[i][j],a[i]+k,INF);
                    }
                    cost-=a[i];
                }
                else
                {
                    g_flow_add(id[i][j],id[i+1][j],INF);
                    g_flow_add(id[i][j],id[i][j-1],INF);
                }
                if(cost>0)
                {
                    g_flow_add(s,id[i][j],cost);
                    ans+=1ll*cost;
                }
                else if(cost<0)
                {
                    g_flow_add(id[i][j],t,-cost);
                }
            }
        }
        if(m)
        {
            for(int i=1;i<=maxa;i++)
            {
                g_flow_add(++k,2,i*i);
            }
        }
        printf("%lld\n",ans-g_flow_dinic());
        return 0;
    }
}
posted @ 2022-05-07 11:14  Day_Dreamer_D  阅读(35)  评论(0)    收藏  举报