题目:

1010: 魔兽争霸之最后的反击

                                                                        Time Limit: 1000 MS Memory Limit: 65536 KB

Description

相传人族与兽族对峙了很久,双方均受到了重创,兽族趁人类没有能力发起大规模进攻之时突然袭击,想一次彻底打败人族。人类为了生存,无论老幼伤病,全部参战,兵分两路抗敌。

由于体质不同,我们以血量表示一个人的战斗力,现在给你所有人的血量,请你把人类分成战斗力最接近的两部分。注意,战斗力要最接近,不然,人族会因你而战败呦!

Input

第一行为一个整数n(1<=n<=36),表示人族的总人数。以下的n行每行一个整数,表示一个人的血量mi(即战斗力),其中1<=mi<=400.

Output

只有一行,包含两个数,即人族的每部分兵的血量总和,较小的一个值放在前面,两个数用空格分隔。

Sample Input

3

20

32

35

Sample Output

35 52

Source

SWUST



解题心得:

1、可以直接价将最大的战斗值/2,然后动态规划就行了。在规划的过程中状态有几种转移的方法。注意此题记录的都是状态(只有false和true),因为记录的是状态所以开的数组直接是bool类型就可以了,第一维是记录的物品的个数,第二维记录的是在选择第k个物品(人族的群数)的时候有多少种可能的重量(战斗力)。当可以达到这个重量的时候将这个重量记录为true。

第一种:

就是很简单的记录人群的数量和总的战斗力,直接给代码.

关于核心的动态规划解释一下:第k件物品,可以选择不装入,所以选择第k件物品的重量就是和第k-1个相同物品的状态相同。也可以选择装入,装入就必须第前一个状态【k-1】的 j-t[j] 要是true才可以转移到这个状态。

#include<bits/stdc++.h>
using namespace std;
bool dp[40][16000];//只是记录的状态bool就可以了,甚至bitset也可以;
int t[40];
int main()
{
int n;
int sum ;
while(~scanf("%d",&n))
{
memset(dp,0,sizeof(dp));
sum = 0;
for(int i=1;i<=n;i++)
{
scanf("%d",&t[i]);
sum += t[i];
}
dp[0][0] = 1;
for(int i=1;i<=n;i++)
{
for(int j=sum;j>=0;j--)
{
for(int k=1;k<=n;k++)
dp[k][j] = dp[k-1][j] | dp[k-1][j-t[k]];//这个是核心算法
}
}
for(int i=sum/2;i>=0;i--)
{
if(dp[n][i])
{
printf("%d %d\n",i,sum-i);
break;
}
}
}
}


第二种:使用滚动数组优化
因为只有前后的状态转移所以数组的第一维只需要开2就可以了,因为true都不变(可以选择不放入),所以状态的转移是将下一个的false在上一个的true之上改变为true。说不清楚了,直接贴代码。
#include<bits/stdc++.h>
using namespace std;
bool dp[2][16000];
int t[40];
int main()
{
int n;
int sum ;
while(~scanf("%d",&n))
{
memset(dp,0,sizeof(dp));
sum = 0;
for(int i=1;i<=n;i++)
{
scanf("%d",&t[i]);
sum += t[i];
}
dp[0][0] = 1;
int now;
for(int i=1;i<=n;i++)
{
for(int j=sum;j>=0;j--)
{
if(j >= t[i])
dp[i%2][j] = dp[(i+1)%2][j] | dp[(i+1)%2][j-t[i]];
else
{
if(dp[(i+1)%2][j])
dp[i%2][j] = 1;
}
}
now = i;//用来记录最后的那个数组,写的好弱智;
}
for(int i=sum/2;i>=0;i--)
{
if(dp[now%2][i])
{
printf("%d %d\n",i,sum-i);
break;
}
}
}
}

第三种:开一个一维数组直接转移就可以了

其实思想也很简单,这个状态转移不是从前面一次到后面转移,而是从后面往前面转移,所以后面的状态不会影响前面的状态,直接转移就可以了。

#include<bits/stdc++.h>
using namespace std;
bool dp[16000];
int t[40];
int main()
{
int n;
int sum ;
while(~scanf("%d",&n))
{
memset(dp,0,sizeof(dp));
sum = 0;
for(int i=1;i<=n;i++)
{
scanf("%d",&t[i]);
sum += t[i];
}
dp[0] = 1;
for(int i=1;i<=n;i++)
for(int j=sum;j>=0;j--)
{
dp[j] = dp[j] | dp[j-t[i]];
}
for(int i=sum/2;i>=0;i--)
{
if(dp[i])
{
printf("%d %d\n",i,sum-i);
break;
}
}
}
}

动态规划(入门,滚动数组,记录的都是状态):SWUSTACM-1010 魔兽争霸之最后的反击的更多相关文章

  1. 【动态规划】滚动数组的求解(C++)

    虽然接触动态规划算法已经有一段时间,给一个01背包问题,能够做到一个表格简单粗暴下去,然后求得结果,但心里总觉得对这个算法理解十分不到位,抱着对算法的热爱,网上很多大牛的算法思维实在让我佩服的五体投地 ...

  2. POJ_1159 Palindrome (线性动态规划+滚动数组)

    题意是说,给定一个字符串,问至少还需要插入多少个字符才能使得该字符串成为回文字符串. 这道题一开始做的时候用了一个简单的动态规划,开了一个5000*5000的数组,用递归形式实现,代码如下: 其中d[ ...

  3. HDU-1024 Max Sum Plus Plus 动态规划 滚动数组和转移优化

    题目链接:https://cn.vjudge.net/problem/HDU-1024 题意 给n, m和一个序列,找m个不重叠子串,使这几个子串内元素和的和最大. n<=1e6 例:1 3 1 ...

  4. POJ-1038 Bugs Integrated, Inc. (状压+滚动数组+深搜 的动态规划)

    本题的题眼很明显,N (1 <= N <= 150), M (1 <= M <= 10),摆明了是想让你用状态压缩dp. 整个思路如下:由于要填2*3或者3*2的芯片,那么就要 ...

  5. NOIP 2006 金明的预算方案(洛谷P1064,动态规划递推,01背包变形,滚动数组)

    一.题目链接:P1064 金明的预算方案 二.思路 1.一共只有五种情况 @1.不买 @2.只买主件 @3.买主件和附件1(如果不存在附件也要运算,只是这时附件的数据是0,也就是算了对标准的结果也没影 ...

  6. 2021.12.10 P2516 [HAOI2010]最长公共子序列(动态规划+滚动数组)

    2021.12.10 P2516 [HAOI2010]最长公共子序列(动态规划+滚动数组) https://www.luogu.com.cn/problem/P2516 题意: 给定字符串 \(S\) ...

  7. 动态规划+滚动数组 -- POJ 1159 Palindrome

    给一字符串,问最少加几个字符能够让它成为回文串. 比方 Ab3bd 最少须要两个字符能够成为回文串 dAb3bAd 思路: 动态规划 DP[i][j] 意味着从 i 到 j 这段字符变为回文串最少要几 ...

  8. 【动态规划】【滚动数组】【bitset】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem J. Terminal

    有两辆车,容量都为K,有n(10w)个人被划分成m(2k)组,依次上车,每个人上车花一秒.每一组的人都要上同一辆车,一辆车的等待时间是其停留时间*其载的人数,问最小的两辆车的总等待时间. 是f(i,j ...

  9. 【Java】【滚动数组】【动态规划】UVA - 11137 - Ingenuous Cubrency

    滚动数组优化自己画一下就明白了. http://blog.csdn.net/u014800748/article/details/45849217 解题思路:本题利用递推关系解决.建立一个多段图,定义 ...

随机推荐

  1. SharePoint 2010开发方面的课堂中整理有关问题

    SharePoint 2010开发方面的课堂中整理有关问题 这是我这几天在做一个SharePoint开发的课程的时候,大家提出的一些问题,及我的解答,分享给更多的朋友参考一下 这个文档,也可以在这里下 ...

  2. 4.0.3的mongodb 安装和java使用

    一 整合 由于本人的码云太多太乱了,于是决定一个一个的整合到一个springboot项目里面. 附上自己的github项目地址 https://github.com/247292980/spring- ...

  3. net start命令发生系统错误5和错误1058的解决方法

    net start命令用于开启服务,格式为:net start [服务名](与之对应的"net stop [服务名]"为关闭服务命令) 5是没有管理员权限,右键管理员即可 1058 ...

  4. vnc安装问题

    在xenserver中安装vncserver软件.启动显示正常 用grep命令查看也确实有线程在运行. 但实际上用命令service vncserver status查看vnc状态,显示没有桌面在运行 ...

  5. Sqlserver列出所有数据库名,表名,字段名【转】

    1.获取所有数据库名: SELECT Name FROM Master..SysDatabases ORDER BY Name 注意: 表Master与SysDatabases之间有两个点 2.获取所 ...

  6. cms-后台eazyui搭建

    1.引入eazyUi需要的js 2.布局:上.下.左.中 <%@ page language="java" contentType="text/html; char ...

  7. linux 命令——36 diff(转)

    diff命令是 linux上非常重要的工具,用于比较文件的内容,特别是比较两个版本不同的文件以找到改动的地方.diff在命令行中打印每一个行的改动.最新版本的diff还支持二进制文件.diff程序的输 ...

  8. js中(break,continue,return)的区别

    break 一般用于跳出整个循环(for,while) continue  跳出本次循环,进入下一次循环 return 只能出现在函数体内,一旦执行return,后面的代码将不会执行,经常用retur ...

  9. Ajax的open方法

    Ajax的open()方法有3个参数:1.method:2.url:3.boolean: 参数1有get和post两个取值 参数2是表单的action属性值 参数3:boolean的取值 当该bool ...

  10. 关于profile集合

    profile集合是mongodb的慢操作日志 > db.getProfilingStatus() { , , } 可以通过getProfilingStatus来查看当前profile设置 pr ...