1.方块与收纳盒
现在有一个大小n*1的收纳盒,我们手里有无数个大小为1*1和2*1的小方块,我们需要用这些方块填满收纳盒,请问我们有多少种不同的方法填满这个收纳盒。
正确代码:
//dp
#include<bits/stdc++.h>
using namespace std;
long dp[100];
int main()
{
dp[1]=1;
dp[2]=2;
for(int i=3;i<100;i++)
dp[i]=dp[i-2]+dp[i-1];
int n;
cin>>n;
while(n--)
{
int a;cin>>a;
cout<<dp[a]<<endl;
}
return 0;
}
总结:这是一道经典的动态规划算法题:
规律: 空间4 由空间3的所有方法(1*1的包)+空间2的所有的方法(1*2的包)。
2.给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
示例 1:
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
- 穷举分析
- 确定边界
- 找规律,确定最优子结构
- 状态转移方程
一:
- 当nums只有一个元素10时,最长递增子序列是[10],长度是1.
- 当nums需要加入一个元素9时,最长递增子序列是[10]或者[9],长度是1。
- 当nums再加入一个元素2时,最长递增子序列是[10]或者[9]或者[2],长度是1。
- 当nums再加入一个元素5时,最长递增子序列是[2,5],长度是2。
- 当nums再加入一个元素3时,最长递增子序列是[2,5]或者[2,3],长度是2。
- 当nums再加入一个元素7时,,最长递增子序列是[2,5,7]或者[2,3,7],长度是3。
- 当nums再加入一个元素101时,最长递增子序列是[2,5,7,101]或者[2,3,7,101],长度是4。
- 当nums再加入一个元素18时,最长递增子序列是[2,5,7,101]或者[2,3,7,101]或者[2,5,7,18]或者[2,3,7,18],长度是4。
- 当nums再加入一个元素7时,最长递增子序列是[2,5,7,101]或者[2,3,7,101]或者[2,5,7,18]或者[2,3,7,18],长度是4.
二:
如果新加入一个元素nums[i], 最长递增子序列要么是以nums[i]结尾的递增子序列,要么就是nums[i-1]的最长递增子序列。
(其实,nums[i]结尾的自增子序列,只要找到比nums[i]小的子序列,加上nums[i] 就可以啦。显然,可能形成多种新的子序列,我们选最长那个,就是dp[i]的值。)
三:
dp(i) =max(dp(j))+1,存在j属于区间[0,i-1],并且num[i]>num[j]。
正确代码:
class Solution {
public int lengthOfLIS(int[] nums) {
if (nums.length == 0) {
return 0;
}
int[] dp = new int[nums.length];
//初始化就是边界情况
dp[0] = 1;
int maxans = 1;
//自底向上遍历
for (int i = 1; i < nums.length; i++) {
dp[i] = 1;
//从下标0到i遍历
for (int j = 0; j < i; j++) {
//找到前面比nums[i]小的数nums[j],即有dp[i]= dp[j]+1
if (nums[j] < nums[i]) {
//因为会有多个小于nums[i]的数,也就是会存在多种组合了嘛,我们就取最大放到dp[i]
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
//求出dp[i]后,dp最大那个就是nums的最长递增子序列啦
maxans = Math.max(maxans, dp[i]);
}
return maxans;
}
}
源引:https://zhuanlan.zhihu.com/p/365698607
3.舔狗舔到最后一无所有
作为队伍的核心,forever97很受另外两个队友的尊敬。
Trote_w每天都要请forever97吃外卖,但很不幸的是宇宙中心forever97所在的学校周围只有3家forever97爱吃的外卖。
如果Trote_w给forever97买了别家的外卖,forever97就会大喊“我不吃我不吃”。
但是forever97又不喜欢连续三天吃一种外卖。
如果Trote_w哪天忘了这件事并且三天给他买了同一家外卖,那么forever97就会把Trote_w的头摁进手机屏幕里。
作为Trote_w的好朋友,你能告诉他连续请forever97吃n天饭,有多少不同的购买方法吗?
多组样例 第一行一个整数T(1<=T<=20)代表测试样例数 接下来t行每行一个整数n,代表Trote_w要请forever97吃n天饭(1<=n<=100000)
输出T个整数代表方案数,由于答案太大,你只需要输出mod 1e9+7 后的答案即可。
示例1
正确代码:
#include<bits/stdc++.h>
using namespace std;
long long dp[100000];
const int maxt=1e9+7;
int main()
{
//因为买1餐厅和2,3是一样的,所以只求其中一个,再乘3
//由题意 如果第i天买了1,则可以加上第i-1买2,3的所有情况 dp[i]+=dp[i-1]*2
//如果第i-1也买1,则第i-2一定不能买1
// 所以第i-1天买1的情况 - 第i-2天买1的所有情况(即i-3天选2、3,因为以及有两天选1了)
//即: dp[i-1]-dp[i-3]*2
//注意:每一天其实都是经过求模后的结果,所以在关系式中也要求模计算
dp[1]=1;
dp[2]=3;
dp[3]=8;
for(int i=4;i<100000;i++)
{
dp[i] = ((dp[i-1]*3%maxt-dp[i-3]*2%maxt)+maxt)%maxt;
}
int n;
cin>>n;
while(n--)
{
int a;
cin>>a;
printf("%lld\n",dp[a]*3%maxt);
}
}