zoukankan      html  css  js  c++  java
  • 【BZOJ4254】Aerial Tramway 树形DP

    【BZOJ4254】Aerial Tramway

    题意:给你一座山上n点的坐标,让你在山里建m条缆车,要求缆车两端的高度必须相等,且中间经过的点的高度都小于缆车的高度。并且不能存在一个点位于至少k条缆车的下方。求缆车的最大总长度。

    n,m<=200,k<=10。

    题解:这么神奇的题面居然有人能想到要用树形DP。。。

    先枚举所有可能的缆车,然后暴力得出这些缆车的关系。因为上面的缆车一定比它下面的缆车长,所以这形成了一个树形结构,我们建树跑树形DP。

    用f[x][a][b]表示x的子树中已经减了y个缆车,且一个点最多位于k条缆车下方,的最大总长度。转移时是惯用的树形背包套路,然后用前缀最大值优化一下即可。时间复杂度O(n*m*k)。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <vector>
    using namespace std;
    int T,n,m,K,tot,ans,cas;
    int x[210],y[210],v[210],bel[210],siz[210],g[210][15],f[210][210][15],d[210];
    vector<int> ch[210];
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    void dfs(int x)
    {
    	siz[x]=1;
    	int i,j,k,l,y;
    	for(l=0;l<=K;l++)	f[x][0][l]=0;
    	for(i=0;i<(int)ch[x].size();i++)
    	{
    		y=ch[x][i],dfs(y);
    		memcpy(g,f[x],sizeof(f[x]));
    		for(j=0;j<=siz[x]&&j<=m;j++)	for(k=0;k<=siz[y]&&j+k<=m;k++)	for(l=0;l<=K;l++)
    			g[j+k][l]=max(g[j+k][l],f[x][j][l]+f[y][k][l]);
    		siz[x]+=siz[y];
    		for(j=0;j<=siz[x]&&j<=m;j++)	for(l=1;l<=K;l++)	f[x][j][l]=max(g[j][l],f[x][j][l-1]);
    	}
    	for(j=min(m,siz[x]);j>=1;j--)	for(l=1;l<=K;l++)
    	{
    		f[x][j][l]=max(f[x][j][l],f[x][j-1][l-1]+v[x]);
    		f[x][j][l]=max(f[x][j][l],f[x][j][l-1]);
    	}
    	ans=max(ans,f[x][m][K]);
    }
    void work()
    {
    	tot=0,K--;
    	int i,j;
    	for(i=1;i<=n;i++)	x[i]=rd(),y[i]=rd(),ch[i].clear(),bel[i]=0;
    	for(i=1;i<=n;i++)
    	{
    		for(j=i-1;j>=1;j--)
    		{
    			if(y[j]>y[i])	break;
    			if(y[j]==y[i])
    			{
    				bel[i]=++tot,v[tot]=x[i]-x[j],d[tot]=0;
    				break;
    			}
    		}
    		if(y[j]==y[i]&&bel[i])	for(j++;j<i;j++)	if(y[j]<y[i]&&bel[j]&&!d[bel[j]])
    			d[bel[j]]=1,ch[bel[i]].push_back(bel[j]);
    	}
    	memset(f,0xc0,sizeof(f));
    	v[++tot]=-1<<20;
    	for(i=1;i<tot;i++)	if(!d[i])	ch[tot].push_back(i);
    	ans=-1,dfs(tot);
    	printf("%d
    ",ans);
    }
    int main()
    {
    	while(scanf("%d%d%d",&n,&m,&K)!=EOF)
    	{
    		printf("Case %d: ",++cas);
    		work();
    	}
    	return 0;
    }//14 3 3 1 8 2 6 3 4 4 6 5 3 6 4 7 1 8 4 9 6 10 4 11 6 12 5 13 6 14 8 14 3 2 1 8 2 6 3 4 4 6 5 3 6 4 7 1 8 4 9 6 10 4 11 6 12 5 13 6 14 8 
  • 相关阅读:
    P1613 跑路
    数据挖掘-聚类分析(Python实现K-Means算法)
    使用scikit-learn 估计器分类
    数据挖掘-集成学习
    数据挖掘-关联分析 Apriori算法和FP-growth 算法
    scikit-learn 中常用的评估模型
    数据挖掘---支持向量机(SVM)
    数据挖掘-KNN-K最近邻算法
    数据挖掘-决策树
    数据挖掘-逻辑Logistic回归
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7749466.html
Copyright © 2011-2022 走看看