#1043 : 完全背包 20160516

时间限制:20000ms
单点时限:1000ms
内存限制:256MB

描述

且说之前的故事里,小Hi和小Ho费劲心思终于拿到了茫茫多的奖券!而现在,终于到了小Ho领取奖励的时刻了!

等等,这段故事为何似曾相识?这就要从平行宇宙理论说起了………总而言之,在另一个宇宙中,小Ho面临的问题发生了细微的变化!

小Ho现在手上有M张奖券,而奖品区有N种奖品,分别标号为1到N,其中第i种奖品需要need(i)张奖券进行兑换,并且可以兑换无数次,为了使得辛苦得到的奖券不白白浪费,小Ho给每件奖品都评了分,其中第i件奖品的评分值为value(i),表示他对这件奖品的喜好值。现在他想知道,凭借他手上的这些奖券,可以换到哪些奖品,使得这些奖品的喜好值之和能够最大。

提示一: 切,不就是0~1变成了0~K么

提示二:强迫症患者总是会将状态转移方程优化一遍又一遍

提示三:同样不要忘了优化空间哦!

输入

每个测试点(输入文件)有且仅有一组测试数据。

每组测试数据的第一行为两个正整数N和M,表示奖品的种数,以及小Ho手中的奖券数。

接下来的n行描述每一行描述一种奖品,其中第i行为两个整数need(i)和value(i),意义如前文所述。

测试数据保证

对于100%的数据,N的值不超过500,M的值不超过10^5

对于100%的数据,need(i)不超过2*10^5, value(i)不超过10^3

输出

对于每组测试数据,输出一个整数Ans,表示小Ho可以获得的总喜好值。

样例输入
5 1000
144 990
487 436
210 673
567 58
1056 897
样例输出
5940

思路:看题目给出的提示会比较清楚。
import java.util.Scanner;

public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
int n = sc.nextInt();
int m = sc.nextInt();
int[] need = new int[n+1];
int[] value = new int[n+1];
for (int i = 1; i <= n; i++) {
need[i] = sc.nextInt();
value[i] = sc.nextInt();
}
int[][] max = new int[2][m+1];
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (i % 2 == 0) {
if (j >= need[i]) {
max[0][j] = Math.max(max[0][j - need[i]] + value[i], max[1][j]);
} else {
max[0][j] = max[1][j];
}
} else {
if (j >= need[i]) {
max[1][j] = Math.max(max[1][j - need[i]] + value[i], max[0][j]);
} else {
max[1][j] = max[0][j];
}
}
}
}
if (n % 2 == 0)
System.out.println(max[0][m]);
else
System.out.println(max[1][m]);
}
}
}

#1038 : 01背包 20160512

时间限制:20000ms
单点时限:1000ms
内存限制:256MB

描述

且说上一周的故事里,小Hi和小Ho费劲心思终于拿到了茫茫多的奖券!而现在,终于到了小Ho领取奖励的时刻了!

小Ho现在手上有M张奖券,而奖品区有N件奖品,分别标号为1到N,其中第i件奖品需要need(i)张奖券进行兑换,同时也只能兑换一次,为了使得辛苦得到的奖券不白白浪费,小Ho给每件奖品都评了分,其中第i件奖品的评分值为value(i),表示他对这件奖品的喜好值。现在他想知道,凭借他手上的这些奖券,可以换到哪些奖品,使得这些奖品的喜好值之和能够最大。

提示一:合理抽象问题、定义状态是动态规划最关键的一步

提示二:说过了减少时间消耗,我们再来看看如何减少空间消耗

输入

每个测试点(输入文件)有且仅有一组测试数据。

每组测试数据的第一行为两个正整数N和M,表示奖品的个数,以及小Ho手中的奖券数。

接下来的n行描述每一行描述一个奖品,其中第i行为两个整数need(i)和value(i),意义如前文所述。

测试数据保证

对于100%的数据,N的值不超过500,M的值不超过10^5

对于100%的数据,need(i)不超过2*10^5, value(i)不超过10^3

输出

对于每组测试数据,输出一个整数Ans,表示小Ho可以获得的总喜好值。

样例输入
5 1000
144 990
487 436
210 673
567 58
1056 897
样例输出
2099

思路:题目提示所给思路说的非常清楚。首先得想到动态规划这种做法,因为这个问题符合动态规划的两个特征重复的子问题和无后效性(具体见提示一)。动态规划时,关键就是在第n个奖品的兑换,有兑换和不兑换两种状态(对应着01背包的1和0),兑换和不兑换的总喜好值较大值就是到第n个奖品时最大总喜好值。

也就是公式:max[i][j] = max{value[i] + max[i-1][j-need[i]], max[i-1][j]},

需要注意的就是这只在j>= need[i]时,才成立,j < need[i]时 max[i][j] = max[i-1][j]。

所以最容易想到 int[][] max = new int[n+1][m+1];然后两个循环求出max[n][m],这样一来空间复杂度就不够简化了。进一步思考发现max只有前后的依赖关系,所以只用保证前一个保存下来就能求出后一个了,所以可简化为 O(2*m)的空间复杂度。提示二中还给出了O(m)的空间复杂度,可以继续思考。

import java.util.Scanner;

public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
int n = sc.nextInt();
int m = sc.nextInt();
int[] need = new int[n+1];
int[] value = new int[n+1];
for (int i = 1; i <= n; i++) {
need[i] = sc.nextInt();
value[i] = sc.nextInt();
}
//MTE n*m的数组,内存超过限制
/* int[][] max = new int[n+1][m+1];
for (int i = 1; i <= n; i++) {
for (int j = 1;j <= m; j++) {
if (j >= need[i]) {
max[i][j] = Math.max(value[i] + max[i-1][j-need[i]], max[i-1][j]);
} else {
max[i][j] = max[i-1][j];
}
}
}
System.out.println(max[n][m]);
*/
//只用 2*m的空间,因为max只有前后的依赖关系,已经可以AC了
/* int[][] max = new int[2][m+1];
for (int i = 1; i <= n; i++) {
for (int j = 1;j <= m; j++) {
if (i %2 == 0) {
if (j >= need[i]) {
max[0][j] = Math.max(value[i] + max[1][j-need[i]], max[1][j]);
} else {
max[0][j] = max[1][j];
}
} else {
if (j >= need[i]) {
max[1][j] = Math.max(value[i] + max[0][j-need[i]], max[0][j]);
} else {
max[1][j] = max[0][j];
}
}
}
}
if (n % 2 == 0)
System.out.println(max[0][m]);
else
System.out.println(max[1][m]);
*/
//只用m的空间,实在是没理解
int[] max = new int[m+1];
for (int i = 1; i <= n; i++) {
for (int j = m; j >= need[i]; j--) {
max[j] = Math.max(max[j], max[j-need[i]]+value[i]);
}
}
System.out.println(max[m]);
}
}
}

思考了一下,感觉贪心算法也能实现,但是想到的复杂度会略高:原则为单位价值最大且重量最小,不超过背包最大承重量为约束条件。也就是说,存在单位重量价值相等的两个包,则选取重量较小的那个背包。

#1032 : 最长回文子串  20160508

时间限制:1000ms
单点时限:1000ms
内存限制:64MB

描述

小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进。

这一天,他们遇到了一连串的字符串,于是小Hi就向小Ho提出了那个经典的问题:“小Ho,你能不能分别在这些字符串中找到它们每一个的最长回文子串呢?”

小Ho奇怪的问道:“什么叫做最长回文子串呢?”

小Hi回答道:“一个字符串中连续的一段就是这个字符串的子串,而回文串指的是12421这种从前往后读和从后往前读一模一样的字符串,所以最长回文子串的意思就是这个字符串中最长的身为回文串的子串啦~”

小Ho道:“原来如此!那么我该怎么得到这些字符串呢?我又应该怎么告诉你我所计算出的最长回文子串呢?

小Hi笑着说道:“这个很容易啦,你只需要写一个程序,先从标准输入读取一个整数N(N<=30),代表我给你的字符串的个数,然后接下来的就是我要给你的那N个字符串(字符串长度<=10^6)啦。而你要告诉我你的答案的话,只要将你计算出的最长回文子串的长度按照我给你的顺序依次输出到标准输出就可以了!你看这就是一个例子。”

提示一 提示二 提示三 提示四

样例输入
3
abababa
aaaabaa
acacdas
样例输出
7
5
3

个人认为这篇博客分析的比较好,虽然我是按照提示一步一步写出来的。

提交时发现必须在头尾加入两个不同的特殊字符,我下面这种方式没有在头尾加,提交we了,没想明白(详见代码中/**/注释的那一段)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader; public class Main {
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String s = "";
while ((s = br.readLine()) != null) {
int t = Integer.parseInt(s);
for (int i = 0;i < t;i++) {
String str = br.readLine();
StringBuilder sb = new StringBuilder();
sb.append("$#");
//在原字符串每个相邻字符串中间插入'#'
for (int j = 0;j < str.length();j++) {
sb.append(str.charAt(j)+"#");
}
sb.append("&");
str = sb.toString();
/*把添加特殊字符那一段修改一下就不对了,没想明白,我看出来的现象是必须在头尾加入两个不同的特殊字符,
我下面这种方式没有在头尾加,提交we了
    

//在原字符串每个相邻字符串中间插入'^'
for (int j = 0;j < str.length()-1;j++) {
sb.append(str.charAt(j)+"^");
}
sb.append(str.charAt(str.length()-1));
str = sb.toString();

*/
int ans = 1,maxj = 0,maxjk = 0,pos = 0;
int[] ls = new int[str.length()];
for (int j = 0;j < str.length();j++) {
//获得当前j为中心的回文子串的最小长度
int k = 0;
if (2*maxj-j < 0) {
k = Math.min(0, ls[maxj]-2*(j-maxj))/2;
} else {
k = Math.min(ls[2*maxj-j], ls[maxj]-2*(j-maxj))/2;
}
k = k > 0 ? k : 0;
ls[j] += 2*k+1;
k++;
while (((j-k) >= 0) && ((j+k) < str.length())) {
if (str.charAt(j-k) == str.charAt(j+k)) {
ls[j] += 2; //记录以每一个字符为中心时的最大回文长度
if (j+k > maxjk) {
maxj = j; //记录使右边界最大的j
maxjk = j+k; //记录右边界的最大值
}
k++;
} else {
break;
}
}
//更新最大回文子串长度与中心字符的位置
if (ls[j] > ans) {
ans = ls[j];
pos = j;
}
}
//去掉其中的特殊字符'^'
if (pos % 2 == 0) {
if (ans >= 3) {
ans = ans-2*((ans-3)/4+1);
}
} else {
ans = ans-2*((ans-1)/4)-1;
}
System.out.println(ans);
}
}
}
}
 

HihoCoder的更多相关文章

  1. hihocoder -1121-二分图的判定

    hihocoder -1121-二分图的判定 1121 : 二分图一•二分图判定 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 大家好,我是小Hi和小Ho的小伙伴Net ...

  2. Hihocoder 太阁最新面经算法竞赛18

    Hihocoder 太阁最新面经算法竞赛18 source: https://hihocoder.com/contest/hihointerview27/problems 题目1 : Big Plus ...

  3. hihoCoder太阁最新面经算法竞赛15

    hihoCoder太阁最新面经算法竞赛15 Link: http://hihocoder.com/contest/hihointerview24 题目1 : Boarding Passes 时间限制: ...

  4. 【hihoCoder 1454】【hiho挑战赛25】【坑】Rikka with Tree II

    http://hihocoder.com/problemset/problem/1454 调了好长时间,谜之WA... 等我以后学好dp再来看为什么吧,先弃坑(╯‵□′)╯︵┻━┻ #include& ...

  5. 【hihocoder#1413】Rikka with String 后缀自动机 + 差分

    搞了一上午+接近一下午这个题,然后被屠了个稀烂,默默仰慕一晚上学会SAM的以及半天4道SAM的hxy大爷. 题目链接:http://hihocoder.com/problemset/problem/1 ...

  6. 【hihoCoder】1148:2月29日

    问题:http://hihocoder.com/problemset/problem/1148 给定两个日期,计算这两个日期之间有多少个2月29日(包括起始日期). 思路: 1. 将问题转换成求两个日 ...

  7. 【hihoCoder】1288 : Font Size

    题目:http://hihocoder.com/problemset/problem/1288 手机屏幕大小为 W(宽) * H(长),一篇文章有N段,每段有ai个字,要求使得该文章占用的页数不超过P ...

  8. 【hihoCoder】1082: 然而沼跃鱼早就看穿了一切

      题目:http://hihocoder.com/problemset/problem/1082 输入一个字符串,将其中特定的单词替换成另一个单词   代码注意点: 1. getline(istre ...

  9. 【hihoCoder】1121:二分图一·二分图判定

      题目   http://hihocoder.com/problemset/problem/1121 无向图上有N个点,两两之间可以有连线,共有M条连线. 如果对所有点进行涂色(白/黑),判定是否存 ...

  10. 【hihoCoder】1036 Trie图

    题目:http://hihocoder.com/problemset/problem/1036 给一个词典dict,词典中包含了一些单词words.要求判断给定的一个文本串text中是否包含这个字典中 ...

随机推荐

  1. SOCKET网络编程细节问题3

    SOCKET网络编程快速上手(二)——细节问题(3) 3.SIGPIPE问题 人怕牺牲,我们写的程序也一样,人有死不瞑目,程序又何尝不是?程序跑着跑着,突然就崩掉了.好一点的牺牲前告诉你些打印,差点的 ...

  2. Ionic.Zip.dll文件压缩和解压

    Ionic.Zip.dll文件压缩和解压 下载地址: http://download.csdn.net/detail/yfz19890410/5578515 1.下载Ionic.Zip.dll组件,添 ...

  3. PHP, Python Nginx works together!

    Nginx is so good at delivering requests to many others. Good! Now let's use the nginx upstream modul ...

  4. MBR,boot loader, partition table, backup, recovery, clean 硬盘引导记录,分区表备份,恢复,清空

    linux/unix系统的分区表结构位于硬盘开始的MBR上.MBR上大小为512bytes. MBR=446B启动信息+64B分区表+2B分隔符=512字节 前面的446bytes作为启动信息,启动信 ...

  5. How to install Savanna

    Pre-conditions: openstack has been installed successfully. 解压软件包中的savanna-all.tar.gz安装tar -C / -xzf ...

  6. 利用jquery对ajax操作,详解原理(附代码)

    1. jQuery load() 方法 jQuery load() 方法是简单但强大的 AJAX 方法. load() 方法从服务器加载数据,并把返回的数据放入被选元素中. 语法: $(selecto ...

  7. 浅谈java垃圾回收机制

    今天看thinking in java,里面很详细的谈到java垃圾回收器机制,看完后让我对这神秘的区域有一定的了解,特写一些小总结记录下来. 分两点来说. 第一点:Object.finalize() ...

  8. mysql数据库 触发器简单实例

    触发器(trigger):监视某种情况,并触发某种操作. 触发器创建语法四要素:1.监视地点(table) 2.监视事件(insert/update/delete) 3.触发时间(after/befo ...

  9. 一起来玩echarts系列(二)------echarts图表自适应问题

    为了直观查看公司服务器各个进程占用的内存动态情况,我使用echarts进行数据可视化,具体的实现过程按下不表. 最后实现的效果如图: 然后问题就来了,因UI采用了Bootstrap响应式框架,所以除了 ...

  10. 正经学C#_表达式与其运算符[算术运算符]:《c#入门经典》

    表达式:正如字面意义,它是通过算术运算符来进行运算的数学公式.表达式的意义我们都是很明白的,大白话就是一个公式嘛.不是很难懂. 表达式不是一个单独的存在,必然有操作数或者操作符的.在c#中有操作符有很 ...