前言
这个系列是我和我的同学一起写的,收录了NKOJ的部分题目的题解,用不断更,NK的同学们可以借鉴学习一下,其他学信竞的也可以看一下,刷新一下题库。总帖在这里
点个赞再看叭~
题目
问题描述
某条街上每一公里就有一汽车站,乘车费用如下表:
公里 1— 2---- 3— 4---- 5— 6— 7— 8— 9---- 10
费用 12-- 21-- 31-- 40-- 49-- 58-- 69-- 79-- 90-- 101
而一辆汽车从不行驶超过10公里。某人想行驶n公里,假设他可以任意次换车,请你帮他找到一种乘车方案使费用最小(10公里的费用比1公里小的情况是允许的)。
编一程序:
读入对乘车费用的描述;
算出最小的价格;
输入格式
输入共两行
第一行为10个不超过100的整数,依次表示行驶1~10公里的费用,相邻两数间用空格隔开;
第二行为某人想要行驶的公里数(1~100公里)。
输出格式
输出文件仅一行包含一个整数,表示该测试点的最小费用
样例输入
12 21 31 40 49 58 69 79 90 101
15
样例输出
147
题解
动态规划(dp)
这道题的正解肯定是动规,当然我会讲一点不是正解的东西…
OK啊不瞎扯了先看动归解法好吧。
知周所众,做动规题的第一步是什么?没错,聪明如你,肯定是输入啊!
(你别说我还真忘过写输入)
输入
这道题他没有单独标注数据范围,但是它说了, 公里数为1~100公里,所以我们的数组要开到100。
(好习惯:开数组不要题目说多大就开多大,在空间允许的情况下,尽量能比数据范围大出10左右)
输入代码如下:
int main() {
for(int i=1;i<=10;i++){
scanf("%d",&f[i]);
}
scanf("%d",&n);
}
状态转移方程
知周所众,做动规题的第二步是什么?(这次真没坑)没错,聪明如你,就是把状态转移方程写出来!
状态转移方程是动规的一大难点,只要把这点搞懂,你就离AC只有一步之遥了。
状态转移状态转移,首先你得给这道题定义一个状态。
这道题是“某人”想坐n公里车,求最小的乘车费用,那么可不可以把“某人”坐到每一个站的费用定义成一个状态,然后从前往后递推处理出第n个站的费用呢?答案是:可以的。
那么定义好状态就好办了,想想怎么把一个状态转移成另一个状态。那么既然状态是做到某一个站的费用,那么转移状态就是用一个站的费用推出下一个站的费用呗。
那么由此,就可以列出状态转移方程:dp[i]=min(dp[j]+f[j],dp[i])
其中f数组存的是坐1~10站的费用,j去遍历i前面十个站,即不换乘就能坐到i的站。
现在就简单了啊,输入输出写好,dp双重循环就好了。
dp代码
就知道你爱看这个
#include <bits/stdc++.h>
using namespace std;
int n, f[103];
int main(){
memset(f,0x3f3f3f3f,sizeof f);
for(int i=1;i<=10;i++){
scanf("%d",&f[i]);
}
scanf("%d",&n);
for(int i=2;i<=n;i++){
for(int j=1;j<i;j++){
f[i]=min(f[i],f[j]+f[i-j]);
}
}
printf("%d",f[n]);
}
dfs
搜索我就不细讲了,直接上代码吧:
#include<bits/stdc++.h>
using namespace std;
int n, a[13], ans=0x3f3f3f3f;
void dfs(int k, int mon){
if(k>n)return;
if(k==n){
ans=min(ans,mon);
return;
}
for(int i=1;i<=10;i++)dfs(k+i,mon+a[i]);
}
int main() {
for(int i=1;i<=10;i++)scanf("%d",&a[i]);
scanf("%d",&n);
dfs(0,0);
printf("%d",ans);
}
这个题用搜索做很容易TLE,所以还是乖乖写动规叭~
废话
本蒟蒻没怎么写过题解,如有错误,还请各位大佬指正~