[BZOJ]4873: [Shoi2017]寿司餐厅 最小割 最大权闭合子图

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/baidu_36797646/article/details/86028120

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

可以说是最大权闭合子图的裸题了吧……
对于每个 d i , j d_{i,j} i &lt; j i&lt;j ),权值为 d i , j d_{i,j} ,选了它就必须选 d i + 1 , j d i , j 1 d_{i+1,j}、d_{i,j-1} ,对于每种代号新建一个点,权值为 m x 2 mx^2 ,每个 d i , i d_{i,i} 连向它对应的代号的点,权值为 d i , i a i d_{i,i}-a_i

Code

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=110;
const int inf=2147483647;
int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*f;
}
int n,m,a[Maxn],d[Maxn][Maxn],st,ed;
struct Edge{int y,d,next;}e[Maxn*Maxn<<4];
int last[Maxn*Maxn+2000],len=1;
void ins(int x,int y,int d)
{
    int t=++len;
    e[t].y=y;e[t].d=d;e[t].next=last[x];last[x]=t;
}
void addedge(int x,int y,int d){ins(x,y,d),ins(y,x,0);}
int h[Maxn*Maxn+2000];
bool bfs()
{
    memset(h,0,sizeof(h));h[st]=1;
    queue<int>q;q.push(st);
    while(!q.empty())
    {
        int x=q.front();q.pop();
        for(int i=last[x];i;i=e[i].next)
        {
            int y=e[i].y;
            if(e[i].d>0&&!h[y])h[y]=h[x]+1,q.push(y);
        }
    }
    return h[ed];
}
int dfs(int x,int f)
{
    if(x==ed)return f;
    int s=0,t;
    for(int i=last[x];i;i=e[i].next)
    {
        int y=e[i].y;
        if(e[i].d>0&&h[y]==h[x]+1&&s<f)
        {
            t=dfs(y,min(e[i].d,f-s));
            s+=t;e[i^1].d+=t;e[i].d-=t;
        }
    }
    if(!s)h[x]=0;
    return s;
}
int P(int x,int y){return(x-1)*n+y;}
bool mark[1010];
int main()
{
	int ans=0;
	n=read(),m=read();st=n*n+1001,ed=n*n+1002;
	for(int i=1;i<=n;i++)mark[a[i]=read()]=true;
	for(int i=1;i<=n;i++)
	for(int j=i;j<=n;j++)
	{
		d[i][j]=read();
		if(i<j)addedge(P(i,j),P(i+1,j),inf),addedge(P(i,j),P(i,j-1),inf);
		int v=d[i][j];
		if(i==j)
		{
			v-=a[i];
			addedge(P(i,j),a[i]+n*n,inf);
		}
		if(v>0)ans+=v,addedge(st,P(i,j),v);
		else addedge(P(i,j),ed,-v);
	}
	for(int i=1;i<=1000;i++)if(mark[i])addedge(i+n*n,ed,m*i*i);
	while(bfs())ans-=dfs(st,inf);
	printf("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/baidu_36797646/article/details/86028120