第一次AK,第一次写题解。题目较简单,稍微记录下思路。
题目1:棋盘寻宝
入门级的动态规划题
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:最长不重复子串
由经典问题“最大子段和”想到的思路。
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:货币面值
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:棋盘寻宝扩展
此题应该有较好的解法,原想从第一题的代码基础上拓展的,但是越改问题越多,遂放弃。
情急之下,暴力解决了。还是那句老话,能暴力的最好别想太多,脑力复杂度是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";
}
}