您的位置:首页 > 大数据 > 人工智能

2015 Multi-University Training Contest 9 hdu 5396 Expression

2015-08-19 12:01 148 查看
题意:一个表达式,加不同的括号得到不同的计算顺序,只要有一个计算顺序不同这两个表达式就是不同的。求所有表达式的和。

区间dp +排列组合

一开始我就知道大概可以用区间dp解决,开个二维记录区间[l,r]的所有方案的总和,然后枚举最后一次操作的符号,把每个区间分为两半,因为左边区间的总和可能有几种情况相加而得到a1,a2,a3,我们把其和保存在数组d【l】【k】,k是枚举的,代表最后操作符号的位置,因为原区间【l】【r】的dp值涉及到每个两个小区间【l】【k】、【k+1】【r】的方案数。例如

A(a,b,c) + B(d,e)

由于我们要求每种可能

那么将产生
a+db+dc+d
a+eb+ec+e
可以发现其等价于 2A + 3B A里面的元素都加了两次,B里面的元素都加了3次

转:http://blog.csdn.net/corncsd/article/details/47758975

dp[l][r]的计算方法是枚举最后一个被计算的位置i,设n1=dp[l][i],n2=dp[i+1][r],t1=t[l][i],t2=t[i+1][r]。那么对于加号,对于每个i要加上n1*t2+n2*t1,对于右边不同的组合,左边的数每次都要被加一次,同理左边不同的组合,右边的数每次也要被加一次。因此n1被加了t2次,n2被加了t1次。减法和加法一样。乘法是直接n1*n2。

当时忘记下面的了。。。。。。。

这还没完,注意就算是左边的顺序和右边的顺序的确定,假设左边有f1个符号,右边有f2个符号,也有C[f1+f2][f1]种排法,相当于在f1+f2个位置中选f1个,剩下的给f2,f1和f2中排列的相对顺序不改变,所以还要乘上C[f1+f2][f1]。同理对于每个i,t[l][r]要加上t1*t2*C[f1+f2][f1]。

#include<stdio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
int inf= 1<<30;
int v[110];
int w[110];
int d[102][1100][33];
using namespace std;
int main()
{
	int i,j,k,n,m,T,K,N,V,m1,m2,t;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d%d",&N,&V,&K);
		for(i=0;i<=N;i++){
			for(j=0;j<=V;j++){
				for(k=1;k<=30;k++)
				{
					d[i][j][k]=-inf;		
				}
			}
		}
		for(i=1;i<=N;i++)
		scanf("%d",&w[i]);
		for(i=1;i<=N;i++)
		scanf("%d",&v[i]);
		for(j=V;j>=0;j--)
		{
			if(j>=v[i])
			d[1][j][1]=w[1];	
			else d[1][j][1]=0;
		}
		for(i=2;i<=N;i++)
		{
			for(j=V;j>=1;j--)
			{
				m1=m2=1;
				for(k=1;k<=K;k++)
				{
					t=d[i-1][j][m1];
					if(j>=v[i]&&d[i-1][j][m1]<d[i-1][j-v[i]][m2]+w[i])
					{
						t=d[i-1][j-v[i]][m2]+w[i];
						m2++;
					}
					else m1++;			
					d[i][j][k]=t;
				}
			}
		}
		int ans=d
[V][K];
		if(ans<0)
		ans=0;
		printf("%d\n",ans);
	}
	return 0;
}


其实
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: