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的边。

完了。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#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();
}

 

 

posted @   fcwww  阅读(194)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示