正文

Zju 1234 Chopsticks2006-08-31 00:38:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/cruxd/18033.html

分享到:

2049042 2006-08-31 00:00:06 Accepted 1234 C++ 00:00.39 448K St.Crux 题意:3个数一套,(a1≤a2≤a3),并定义c =(a1 - a2)^2 。在M个已排序数里找出N套这样的数,使得∑c最小。 典型的组合式dp题。这题的关卡在于:数是一套的,而不是一个,而第三个数又是无用的。但是有一点:a1和a2必然是临近的数,(不然必大于这种最优选择)即取到第k个数时,对于ak和ak-1只有两种选择: 1.不取。2.取。(........) 捆绑考虑。 和所有的组合dp一样,可以列出方程: opt[i, k] = opt[i - 1, k - 2] + (ak - ak-1)^2  (1≤i≤n, 1≤k≤m) 且opt[i, k] = opt[i, k - 1] 其中opt表示前k个数里取i个能取到的最小值。其中k对于每个i都有取值范围,两边都有,这个和组合dp一样,只不过稍显复杂一些。 而这显然要优化,数组开这么大,1000×5000,还好现在内存便宜。但是还得优化,n值一大照样破产。 那么,只需要两个数组便可。这个也是老规矩了,上一步的先存在b[0]里,每个做完了放b[1]里,等k循环完一遍就可把b[1]赋值给b[0]。这是一种经常用的手法,也是所有不写注释的程序最让人百思不得其解的地方。 #include <cstdio>#include <string> #define MX 99999999 int a[5001], b[2][5001], c, n, m; void init(){ memset(b, 0, sizeof(b));} void dp(){ int i, k; for(i = 1; i <= m; i ++) {  for(k = 2 * i; k <= n; k ++)  {   b[1][k] = MX;   if(k > 2 * i) b[1][k] = b[1][k - 1];   if(n - k > (m - i) * 3)   {    int t = b[0][k - 2] + (a[k] - a[k - 1]) * (a[k] - a[k - 1]);    if(t < b[1][k]) b[1][k] = t;   }  }  memcpy(b[0], b[1], sizeof(b[1])); }} void prt(){ //pt(); printf("%d\n", b[1][n]);}  int main(){ //freopen("in.txt", "r", stdin); scanf("%d", &c); int i, k; for(i = 0; i < c; i ++) {  scanf("%d %d", &m, &n);  m += 8;  for(k = 1; k <= n; k ++)  {   scanf("%d", &a[k]);  }  init();  dp();  prt(); } return 0;}

阅读(38464) | 评论(7)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册