【SHOI&SXOI2017】bzoj4873 寿司餐厅

177 篇文章 1 订阅
115 篇文章 0 订阅

因为依赖关系比较复杂,而且数据比较小,考虑网络流。
把正负区间根据收益正负和相互之间的依赖关系按最大权闭合子图的方式建图。然后再把单个位置和对应的类别加进去。

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100010,s=100005,t=100006,oo=0x3f3f3f3f;
int fir[maxn],ne[maxn],to[maxn],w[maxn],que[maxn],dep[maxn],cur[maxn],
idr[110][110],ida[1010],idp[110],a[110],d[110][110],
n,m,tot,num;
void add(int u,int v,int x)
{
    num++;
    ne[num<<1]=fir[u];
    fir[u]=num<<1;
    to[num<<1]=v;
    w[num<<1]=x;
    ne[num<<1|1]=fir[v];
    fir[v]=num<<1|1;
    to[num<<1|1]=u;
    w[num<<1|1]=0;
}
int bfs()
{
    int hd=1,tl=1,u,v;
    for (int i=1;i<=tot;i++) dep[i]=0;
    dep[t]=0;
    dep[que[1]=s]=1;
    while (hd<=tl)
    {
        u=que[hd++];
        cur[u]=fir[u];
        for (int i=fir[u];i;i=ne[i])
            if (w[i]&&!dep[v=to[i]])
            {
                que[++tl]=v;
                dep[v]=dep[u]+1;
            }
    }
    return dep[t];
}
int dfs(int u,int lim)
{
    if (u==t) return lim;
    int ret=0,x,v;
    for (int &i=cur[u];i;i=ne[i])
        if (w[i]&&dep[v=to[i]]==dep[u]+1)
        {
            x=dfs(v,min(lim-ret,w[i]));
            ret+=x;
            w[i]-=x;
            w[i^1]+=x;
        }
    return ret;
}
int main()
{
    int ans=0;
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) idp[i]=++tot;
    for (int i=1;i<=n;i++)
        for (int j=i;j<=n;j++)
            idr[i][j]=++tot;
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        if (!ida[a[i]]) ida[a[i]]=++tot;
    }
    for (int i=1;i<=n;i++)
        for (int j=i;j<=n;j++)
        {
            scanf("%d",&d[i][j]);
            if (d[i][j]>=0)
            {
                ans+=d[i][j];
                add(s,idr[i][j],d[i][j]);
            }
            else add(idr[i][j],t,-d[i][j]);
            if (i==j) add(idr[i][j],idp[i],oo);
            else
            {
                add(idr[i][j],idr[i+1][j],oo);
                add(idr[i][j],idr[i][j-1],oo);
            }
        }
    for (int i=1;i<=n;i++)
    {
        add(idp[i],t,a[i]);
        if (m) add(idp[i],ida[a[i]],oo);
    }
    if (m) for (int i=0;i<=1000;i++)
        if (ida[i]) add(ida[i],t,i*i);
    while (bfs()) ans-=dfs(s,oo);
    printf("%d\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值