zoukankan      html  css  js  c++  java
  • 解题报告: luogu P1040

    题目链接:P1040 加分二叉树
    这是我自己独立完成的第一道树形(dp),(qwq)我太弱了。
    其实我并没有用到什么厉害的树上算法(因为我不会),所以考虑把树上问题转化为数列的问题,可以模拟,记录下中断点(也就是树根),然后后面弄成最小字典序的情况(dfs)就行了,有一些玄学问题,虽然不知道为啥,但可以巧妙避免。
    为什么这么考虑呢?
    我也不知道,你看啊,对于每个子树,可以发现编号是连续的,那我们设(f[i][j])为编号从(i)(j)构成子树的最大加分,然后我们从(2)(n)枚举区间长度(l),得到的状态转移方程就是:

    [f[i][i+l-1]=max(f[i][i+l-1],f[i][j-1]×f[j+1][i-l+1]+f[j][j] ]

    (以为自己很(nb),然后发现这是大众方法。)
    这里的(j)是编号(i)(i+l-1)构成子树的根,(f[j][j])就是根的分数。
    注意这里(j+1)可能大于(i-l+1),要处理一下,不要让他是(0)
    这样的复杂度是(O(n^3))的,可以通过本题,不过(n)为什么上界只有(30)呢?

    (Code):

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    ll f[35][35];
    int n,mid[35][35],vis[35];
    void dfs(int l,int r)
    {
    	if(min(l,r)<1||max(l,r)>n) return;
    	if(l>=r)
    	{
    		if(!vis[l]) printf("%d ",l);
    		vis[l]=1;
    		return;
    	}
    	if(!vis[mid[l][r]]) printf("%d ",mid[l][r]);
    	vis[mid[l][r]]=1;
    	dfs(l,mid[l][r]-1);
    	dfs(mid[l][r]+1,r);
    }
    void init(){for(int i=1;i<=n+1;i++)for(int j=1;j<=n;j++)if(i!=j) f[i][j]=1;}
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++) scanf("%lld",&f[i][i]);
    	init();
    	for(int l=2;l<=n;l++)
    	{
    		for(int i=1;i<=n-l+1;i++)
    		{
    			for(int j=i+1;j<=i+l-1;j++)
    			{
    				if(f[i][j-1]*f[j+1][i+l-1]+f[j][j]>f[i][i+l-1]) f[i][i+l-1]=f[i][j-1]*f[j+1][i+l-1]+f[j][j],mid[i][i+l-1]=j;
    			}
    		}
    	}
    	printf("%lld
    ",f[1][n]); 
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=i+1;j<=n;j++) if(mid[i][j]==j) mid[i][j]=i;
    	}
    	dfs(1,n);
    	printf("
    "); 
    	return 0;
    }
    
  • 相关阅读:
    iphone合并.a文件,制作通用静态库
    iphone技巧3
    在windows下安装collabnet subversion server 1.6.5 正确
    iphone技巧2
    iPhone开源库
    盗链,可耻啊
    Jquery ajax 缓存
    js调用服务器端按钮的事件
    电脑删除文件很慢怎么回事?
    解决'System.OutOfMemoryException' 的问题
  • 原文地址:https://www.cnblogs.com/tlx-blog/p/12419531.html
Copyright © 2011-2022 走看看