zoukankan      html  css  js  c++  java
  • P1077 [NOIP2012 普及组] 摆花

    一开始直接将题目按照字面意思翻译成dp,没想太多T了4个点...

    (f(i, j, k))表示摆好前i盆花,最后一种花是j,并且摆了k盆的所有摆法的集合,那么状态计算就是

    (f(i, j, k) = sum_{u=1}^{j-1}sum_{v=1}^{a_u}f(i-k,u,v)),极其复杂,但是确实没错,需要2重循环更新

    初始条件:(f(i, j, k)=1,(i=k))

    #include<iostream>
    using namespace std;
    
    const int mod = 1e6 + 7, N = 110;
    
    int f[N][N][N];
    int n, m;
    int a[N];
    
    int main(){
        cin >> n >> m;
        for(int i = 1; i <= n; i ++) cin >> a[i];
        
        for(int i = 0; i <= m; i ++)
            for(int j = 1; j <= n; j ++)
                for(int k = 0; k <= a[j]; k ++)
                    if(i == k) 
                        f[i][j][k] = 1;
            
        for(int i = 2; i <= m; i ++){
            for(int j = 1; j <= n; j ++)
                for(int k = 1; k <= a[j] && k < i; k ++)
                    for(int u = 1; u < j; u ++)
                        for(int v = 1; v <= a[u]; v ++)
                            f[i][j][k] = (f[i][j][k] % mod + f[i - k][u][v] % mod) % mod;
            
        }
        
        
        int res = 0;
        for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= a[i]; j ++)
                res = (res % mod +  f[m][i][j] % mod) % mod;
                
        cout << res << endl;
        
        return 0;
    }
    

    复杂度:(O(N^5))

    这一题给的必须升序摆放是迷惑信息

    思路二:将问题转化为给定n个数字,每一个数字有一定的取值范围,求出令所有数字总和为n的所有取值方法,方法可以有暴力,记忆化,dp...

    (f(i, j))表示对于前i个数取值,和为j的所有取值方法的集合

    (f(i, j) = sum_{k=0}^{a_i}f(i-1, j-k))

    初始条件:(f(0, 0) =1)

    复杂度:(O(N^3))

    #include<iostream>
    using namespace std;
    
    const int N = 110, mod = 1e6 + 7;
    
    int f[N][N];
    int a[N];
    int n, m;
    
    int main(){
        cin >> n >> m;
        
        for(int i = 1; i <= n; i ++) cin >> a[i];
        
        f[0][0] = 1;
        
        for(int i = 1; i <= n; i ++)
            for(int j = 0; j <= m; j ++)
                for(int k = 0; k <= a[i] && k <= j; k ++)
                    f[i][j] = (f[i][j] % mod + f[i - 1][j - k] % mod) % mod;
                    
        cout << f[n][m] << endl;
        
        return 0;
    }
    

    等价变换代码

    #include<iostream>
    using namespace std;
    
    const int N = 110, mod = 1e6 + 7;
    
    int f[N];
    int a[N];
    int n, m;
    
    int main(){
        cin >> n >> m;
        
        for(int i = 1; i <= n; i ++) cin >> a[i];
        
        f[0] = 1;
        
        for(int i = 1; i <= n; i ++)
            for(int j = m; j >= 0; j --)
              	/*
              		注意此处k要从1开始,因为在二维dp中k从0开始的
              	  	目的是将f[i][j]赋值为f[i - 1][j],而一维情
              	  	况下f[j]已经是f[i - 1][j]了,所以k要从1开始
              	*/
                for(int k = 1; k <= a[i] && k <= j; k ++) 
                    f[j] = (f[j] % mod + f[j - k] % mod) % mod;
                    
        cout << f[m] << endl;
        
        return 0;
    }
    
  • 相关阅读:
    申请加分项
    课程评价
    本周总结
    热词2
    热词1
    php大作业
    css网格布局
    php实验4
    本周总结
    css边框图像
  • 原文地址:https://www.cnblogs.com/tomori/p/15055600.html
Copyright © 2011-2022 走看看