第一次AK,第一次写题解。题目较简单,稍微记录下思路。
题目1:棋盘寻宝
时间限制:1 秒
内存限制:128 兆
特殊判题:否
提交:204
解决:91
-
题目描述:
-
现在有一个8*8的棋盘,上面放着64个价值不等的礼物,每个小的棋盘上面放置一个礼物(礼物的价值大于0小于1000),一个人的初始位置在棋盘的左上角,每次他只能向下或向右移动一步,并拿走对应棋盘上的礼物,结束位置在棋盘的右下角,请设计一个算法使其能够获得最大价值的礼物。
-
输入:
-
输入包含多个测试用例,每个测试用例共有8行8列,第i行的第j列的数字代表了该处棋盘上的礼物的价值,每两个数之间用空格隔开。
-
输出:
-
对于每组测试用例,请输出你能够获得最大价值的礼物。
-
样例输入:
-
2 8 15 1 10 5 19 19 3 5 6 6 2 8 2 12 16 3 8 17 12 5 3 14 13 3 2 17 19 16 8 7 12 19 10 13 8 20 16 15 4 12 3 14 14 5 2 12 14 9 8 5 3 18 18 20 4 2 10 19 17 16 11 3
-
样例输出:
-
194
入门级的动态规划题
dp[i][j]为到i行j列的最大值,逐行逐列计算即可。时间o(n^2)
#include<iostream>
#include<cstring>
using namespace std;
int main(){
int i,j,k,a[9][9],dp[9][9];
memset(dp,0,sizeof(dp));
while(cin>>a[1][1]){
for(i=2;i<=8;i++)
cin>>a[1][i];
for(i=2;i<=8;i++)
for(j=1;j<=8;j++)
cin>>a[i][j];
for(i=1;i<=8;i++)
for(j=1;j<=8;j++)
dp[i][j]=a[i][j]+max(dp[i][j-1],dp[i-1][j]);
cout<<dp[8][8]<<endl;
}
}
题目2:最长不重复子串
时间限制:1 秒
内存限制:128 兆
特殊判题:否
提交:255
解决:72
-
题目描述:
-
最长不重复子串就是从一个字符串中找到一个连续子串,该子串中任何两个字符都不能相同,且该子串的长度是最大的。
-
输入:
-
输入包含多个测试用例,每组测试用例输入一行由小写英文字符a,b,c...x,y,z组成的字符串,字符串的长度不大于10000。
-
输出:
-
对于每组测试用例,输出最大长度的不重复子串长度。
-
样例输入:
-
absd abba abdffd
-
样例输出:
-
4 2 4
由经典问题“最大子段和”想到的思路。
flag[i]记录各个字母首次出现的位置。
遍历该串,当遇到的字符从未出现过时:计数器t++并且记录当前位置。
否则:浮标回退到上次出现的位置的下一个,如果计数器t比ans大则更新ans,并将t置零flag初始化。
思路很简单。比如“sasd”。
"s" t=1
"a" t=2
"s" 出现过,i回退到“a”, ans=2,t=1
“s” t=2
"d" t=3
ans=3
由于最坏情况下遍历串26次,时间o(n)
代码如下
#include<iostream>
#include<cstring>
using namespace std;
int main(){
int flag[26];
char s[10005];
while(cin>>s){
memset(flag,-1,sizeof(flag));
int i,t,ans=1;
for(t=i=0;s[i];i++){
if(flag[s[i]-'a']==-1){
t++;
flag[s[i]-'a']=i;
}else{
i=flag[s[i]-'a'];
memset(flag,-1,sizeof(flag));
if(t>ans)ans=t;
t=0;
}
}
if(t>ans)ans=t;
cout<<ans<<endl;
}
}
题目3:货币面值
时间限制:1 秒
内存限制:128 兆
特殊判题:否
提交:102
解决:49
-
题目描述:
-
小虎是游戏中的一个国王,在他管理的国家中发行了很多不同面额的纸币,用这些纸币进行任意的组合可以在游戏中购买各种装备来提升自己。有一天,他突然很想知道这些纸币的组合不能表示的最小面额是多少,请聪明的你来帮助小虎来解决这个财政问题吧。
-
输入:
-
输入包含多个测试用例,每组测试用例的第一行输入一个整数N(N<=100)表示流通的纸币面额数量,第二行是N个纸币的具体表示面额,取值[1,100]。
-
输出:
-
对于每组测试用例,输出一个整数,表示已经发行的所有纸币都不能表示的最小面额(已经发行的每个纸币面额最多只能使用一次,但面值可能有重复)。
-
样例输入:
-
5 1 2 3 9 100 5 1 2 4 9 100 5 1 2 4 7 100
-
样例输出:
-
7 8 15
0-1背包问题,用一维数组可以简化代码,思路如下
dp[i]=1表示面值i可以被表示,遍历输入的数组a[i],如果dp[j-a[i]]可以被表示,那么dp[j]也应该可以被表示。
01背包一维数组解法不需要sort排序,但有一点要注意,此解法中dp[j]数组一定要倒序遍历。
为方便处理,设置哨兵dp[0]=1。
代码如下:
#include<iostream>
#include<cstring>
using namespace std;
int main(){
int n,a[105],dp[10005];
while(cin>>n){
memset(dp,0,sizeof(dp));
dp[0]=1;
int m=0;
for(int i=0;i<n;i++){
cin>>a[i];
m+=a[i];//m记录所有数值的总和,用以优化后边的循环
}
for(int i=0;i<n;i++)
for(int j=m;j>=a[i];j--)//此循环一定要倒序遍历
dp[j]|=dp[j-a[i]];
for(int i=1;i<10005;i++)
if(!dp[i]){
cout<<i<<endl;
break;
}
}
}
题目4:棋盘寻宝扩展
时间限制:1 秒
内存限制:128 兆
特殊判题:否
提交:100
解决:49
-
题目描述:
-
现在有一个8*8的棋盘,上面放着64个不同价值的礼物,每个小的棋盘上面放置一个礼物(礼物的价值大于0小于100),一个人初始位置在棋盘的左上角,每次他只能向下或向右移动一步,并拿走对应棋盘上的礼物,结束位置在棋盘的右下角。从棋盘的左上角移动到右下角的时候的,每次他只能向下或向右移动一步,并拿走对应棋盘上的礼物,但是拿到的所有的礼物的价值之和不大于一个限定值limit,请设计一个算法请实现,使其能够获得不超过限制值limit的最大价值的礼物。
-
输入:
-
输入包含多个测试用例,每个测试用例共有9行,第一行是一个限制值limit<=1000,下面还有8行8列,第i行的第j列的数字代表了该处棋盘上的礼物的价值,每两个数之间用空格隔开。
-
输出:
-
对于每组测试用例,请输出你能够获得不超过限制值limit的最大价值的礼物。若没有符合条件的线路则输出-1。
-
样例输入:
-
90 4 2 5 1 3 8 9 7 4 5 2 3 7 1 8 6 7 2 1 8 5 9 3 6 2 8 9 5 6 3 1 7 1 2 4 5 3 7 9 6 3 5 7 8 9 6 2 4 10 8 1 4 7 5 3 9 7 4 6 2 1 3 9 8
-
样例输出:
-
90
此题应该有较好的解法,原想从第一题的代码基础上拓展的,但是越改问题越多,遂放弃。
情急之下,暴力解决了。还是那句老话,能暴力的最好别想太多,脑力复杂度是0。
dp[i]记录所有路径到达终点时得总价值,如dp[i]==1表示能取到总价值为i。
递归比较简单,只是往右和往左的分支。
还有个比较重要的剪枝,就是判断当前价值是否大于limit,若超出则结束递归。
代码如下:
#include<iostream>
#include<cstring>
using namespace std;
int limit,a[9][9],dp[1505];
void Bice(int i,int j,int w){
if(w>limit)return;//剪枝
if(i==8&&j==8){
dp[w]=1;
return;
}
if(i<8)Bice(i+1,j,w+a[i+1][j]);
if(j<8)Bice(i,j+1,w+a[i][j+1]);
}
int main(){
int i,j;
while(cin>>limit){
memset(dp,0,sizeof(dp));
for(i=1;i<9;i++)
for(j=1;j<9;j++)
cin>>a[i][j];
Bice(1,1,a[1][1]);
for(i=limit;i;i--)
if(dp[i]){
cout<<i<<endl;
break;
}
if(i==0)
cout<<"-1\n";
}
}