zoukankan      html  css  js  c++  java
  • DP

    多维dp可以使用坐标来表示状态,P1004,就可以将每个方格的f值开为f[i][j][k][l],将两个点分别在(i,j)与(k,l)的状态表示,进行状态转移,对于特定的情况,可以进行降维,P1006,由于传纸条是只能向下和向右传递,所以到达每个点的步数是一定的,为i+j-1(初始点不同表示方法不同,也可以是i+j-2),这样就可以开一个三维数组,f[k][i][j],用k来表示到达这个状态的步数,i,j表示该状态两个点的行(列)数,由于步数与行列数的关系,可以算出该点的行列坐标,进行与四维相同的转移即可,另外一点就是,在这两个题中是要求不能到达同一点,但要求的其实是总和,所以不管哪一点进入该状态都可以,判断(i==j)f-=该点的val;

    p1006转移代码

    1     for(int k=2;k<=n+m-1;k++)
    2     for(int i=1;i<=n&&i<=k;i++)
    3     for(int j=1;j<=n&&j<=k;j++)
    4     {
    5         f[k][i][j]=max(max(max(f[k-1][i-1][j-1],f[k-1][i][j-1]),f[k-1][i-1][j]),f[k-1][i][j])+val[k-i+1][i]+val[k-j+1][j];
    6         if(i==j)f[k][i][j]-=val[k-j+1][j];
    7     }
    8     cout<<f[n+m-1][n][n];

     区间DP【我是谁,我在那?

    对于区间的状态转移个人认为最主要的是最小单元和合并方式,以及状态表示,对于一个区间的操作,如何才能借此推出下一个区间就是一个关键性问题,由于是区间的操作,有可能会出现向左与向右的问题,所以可能会需要加入一个维度来表示区间的左与右,P1220,就是一个典型的在区间上表示左右的题;

    对于大多数的区间DP,记忆化搜索与递推都是可以转换的,记忆化搜索是去除,而递推则是加入,比如P1005,就是一个两种方法均可。对与递推,还有注意一部分的倒序,这样才能保证无后效性,

    区间DP的转换性也是很强的,当一个矩阵行与行之间没有关联时,就可以转变为每一行的区间DP,矩形取数就是这样的一个题。

    P1220

    1 f[s][s][0]=0;f[s][s][1]=0;
    2 for(int i=s;i>=1;i--)for(int j=i+1;j<=n;j++)
    3     {
    4 f[i][j][0]=min(f[i+1][j][0]+(a[i+1]-a[i])*t[i+1][j]
    5               ,f[i+1][j][1]+(a[j]-a[i])*t[i+1][j]);
    6 f[i][j][1]=min(f[i][j-1][0]+(a[j]-a[i])*t[i][j-1]
    7               ,f[i][j-1][1]+(a[j]-a[j-1])*t[i][j-1]);
    8     }
    9     cout<<min(f[1][n][1],f[1][n][0]);

    P1005

     1 a[0]=1;f(i,m)a[i]=a[i-1]*2;
     2 f(i,n)
     3 {    
     4     for(int r=1;r<=m;r++)
     5     for(int l=r;l>=1;l--)
     6     {    k=m-(r-l);
     7     f[l][r]=max(f[l+1][r]+num[i][l]*a[k],f[l][r-1]+num[i][r]*a[k]);
     8     }
     9     ans+=f[1][m];
    10     f(k,m)f(o,m)f[k][o]=0;
    11 }

     做了一点树形DP的题,觉得树形DP感觉很少会出现其他类型,【其实是太弱了

    一类是类似没有上司的舞会,和最大独立集有关的题,另外一类就是树上的分组背包,通过枚举分给每一个子树的权值,感觉很套化,多练一练掌握一下

    而且树上背包个人感觉记忆化搜索更优,比较舒服

    P1270,

    void init(int cnt)
    {
        int a;
        cin>>a>>val[cnt];
        tme[cnt]=a*2;
        if(!val[cnt])
        {
            init(cnt>>1);
            init(cnt>>1|1);
        }
    }
    int dfs(int cnt,int tot)
    {if(f[cnt][tot]>0||!tot)return f[cnt][tot];    
    if(val[cnt])return f[cnt][tot]=min(val[cnt],(tot-tme[cnt])/5);
        for(int i=0;i<=tot-tme[cnt];i++)
        f[cnt][tot]=max(f[cnt][tot],dfs(cnt<<1,i)+dfs(cnt<<1|1,tot-tme[cnt]-i));
        return f[cnt][tot];
    }
    int main()
    {
        cin>>t;
        init(1);
        cout<<dfs(1,t-1);
    }
    论如何枚举所有状态————P1077
    本来以为做那么多题能写出来结果还是失败了
    就差那么一点啊
    再表示一下数量啊喂
    int main()
    {
    	cin>>n>>m;
    	for(int i=0;i<=n;i++)f[i][0]=1;
    	for(int i=1;i<=n;i++)
    	{
    		cin>>a;
    		for(int j=0;j<=a;j++)
    		for(int k=0;k<=m-j;k++)
    		{
    			if(!j&&!k)continue;
    			f[i][j+k]=(f[i-1][k]+f[i][j+k])%mods;
    		}
    	}
    	cout<<f[n][m]%mods;
    }
    
    
    

      



  • 相关阅读:
    mysql 查询当天、本周,本月,上一个月的数据
    Mysql 查看连接数,状态 最大并发数,以及设置连接数
    MySQL慢查询日志优化
    java中线程通信(传统的线程通信)
    java中死锁
    同步锁(lock)
    同步锁(lock)
    释放同步监视器的锁定(java疯狂讲义)
    linux第9天 UDP
    linux第8天 connect强化
  • 原文地址:https://www.cnblogs.com/SFWR-YOU/p/10421555.html
Copyright © 2011-2022 走看看