目录
一.复习动态规划
二.get到了新的知识---赋值问题
三.今日小结
一.复习动态规划
例题1
数字三角形
题目描述
观察下面的数字金字塔。
写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
在上面的样例中,从7 到 3 到 8 到 7 到 5 的路径产生了最大
输入格式
第一个行包含 R(1<= R<=1000) ,表示行的数目。
后面每行为这个数字金字塔特定行包含的整数。
所有的被供应的整数是非负的且不大于100。
输出格式
单独的一行,包含那个可能得到的最大的和。
样例数据
input
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
output
30
分析:动态规划入门题,要想找到整体最优解,则需要使上一步为最优解,故状态转移方程为dg[i][j]=max(dg[i-1][j],dg[i-1][j-1])+n[i][j];
#include<bits/stdc++.h>
using namespace std;
int r;
int n[1100][1100],dg[1100][1100];
int main()
{
freopen("numtri.in","r",stdin);
freopen("numtri.out","w",stdout);
cin>>r;
for(int i=1;i<=r;i++)
for(int j=1;j<=i;j++)
cin>>n[i][j];
dg[1][1]=n[1][1];
for(int i=2;i<=r;i++)
{
for(int j=1;j<=i;j++)
{
dg[i][j]=max(dg[i-1][j],dg[i-1][j-1])+n[i][j];
}
}
int ans=0;
for(int i=1;i<=r;i++) ans=max(ans,dg[r][i]);
cout<<ans<<endl;
return 0;
}
注:此方法为顺推,及由[1][1]开始
例题2
摘花生
题目描述
Hello Kitty想摘点花生送给她喜欢的米老鼠。
她来到一片有网格状道路的矩形花生地(如下图),从西北角进去,东南角出来。
地里每个道路的交叉点上都有种着一株花生苗,上面有若干颗花生,经过一株花生苗就能摘走该它上面所有的花生。
Hello Kitty只能向东或向南走,不能向西或向北走。
问Hello Kitty最多能够摘到多少颗花生。
输入格式
第一行是一个整数T,代表一共有多少组数据。
接下来是T组数据。
每组数据的第一行是两个整数,分别代表花生苗的行数R和列数 C。
每组数据的接下来R行数据,从北向南依次描述每行花生苗的情况。每行数据有C个整数,按从西向东的顺序描述了该行每株花生苗上的花生数目M。
输出格式
对每组输入数据,输出一行,内容为Hello Kitty能摘到得最多的花生颗数。
样例
输入样例
2
2 2
1 1
3 4
2 3
2 3 4
1 6 5
输出样例
8
16
分析:本题与第一题相似。只需要注意初始化即可。状态转移方程为:dp[i][j]=max(dp[i-1][j],dp[i][j-1])+n[i][j];
#include<bits/stdc++.h>
using namespace std;
int t,r,c;
int ans[1100]={};
int a[1100][1100],dp[1100][1100];
int main()
{
freopen("peanut.in","r",stdin);
freopen("peanut.out","w",stdout);
cin>>t;
for(int i=1;i<=t;i++)
{
memset(a,0,sizeof(a));
memset(dp,0,sizeof(dp));
cin>>r>>c;
for(int j=1;j<=r;j++)
{
for(int k=1;k<=c;k++)
{
cin>>a[j][k];
}
}
dp[r][c]=a[r][c];
for(int j=r;j>=1;j--)
{
for(int k=c;k>=1;k--)
dp[j][k]=max(dp[j+1][k],dp[j][k+1])+a[j][k];
}
cout<<dp[1][1]<<endl;
}
return 0;
}
//dp[i][j]=max(dp[i-1][j],dp[i][j-1])+n[i][j];
注:本题方法为逆推,及从结束点倒退到[1][1],相比较于顺推而言,最大的优点在于直接输出dp[1][1]即可。
例题3
公交乘车
题目描述
一个特别的单行街道在每公里处有一个汽车站。顾客根据他们乘坐汽车的公里使来付费。例如下表就是一个费用的单子。
公里数 1 2 3 4 5 6 7 8 9 10
价格 12 21 31 40 49 58 69 79 90 101
没有一辆车子行驶超过10公里,一个顾客打算行驶n公里()1<=n<=100),它可以通过无限次的换车来完成旅程。最后要求费用最少。
输入格式
第一行十个整数分别表示行走1到10公里的费用(<=500)。注意这些数并无实际的经济意义,即行驶10公里费用可能比行驶一公里少。
第二行一个整数n表示,旅客的总路程数。
输出格式
仅一个整数表示最少费用。
样例数据
input
12 21 31 40 49 58 69 79 90 101
15
output
147
分析:状态转移方程:dp[i]=min(dp[i-j]+a[j],dp[i]);
#include<bits/stdc++.h>
using namespace std;
int cost,n;
int a[550],dp[550];
int main()
{
freopen("buses.in","r",stdin);
freopen("buses.out","w",stdout);
for(int i=1;i<=10;i++) cin>>a[i];
cin>>n;
memset(dp,10,sizeof(dp));
dp[0]=0;
dp[1]=a[1];
for(int i=2;i<=n;i++)
{
for(int j=1;j<=i&&j<=10;j++)
{
dp[i]=min(dp[i-j]+a[j],dp[i]);
}
}
cout<<dp[n]<<endl;
return 0;
}
二. get到了新的知识---赋值问题
题目描述
在很多程序设计语言中,忘记给变量赋初值的错误常令人头疼。
在下面的问题中,最开始仅有变量a中有确定的值。变量为单个小写字母, 每行恰好有三个字符,中间一个是赋值运算符'='。
请编程求出含N行的程序段运行以后有哪些变量中有确定的值。
输入格式
第一行:N (0<N<=10^6) 以下N行,每行3个字符,为一条语句.
输出格式
如果没有,输出 none 否则在一行中按字母表顺序给出所有有确定值的变量名,字母之间用空格分隔。
样例数据
input
4
b=a
c=d
d=b
e=f
output
a b d
分析:若将输入的三个字符分别定义为x,equal,y,那么分以下三种情况:
1.x有值,y有值,则操作后x,y均有值
2.x有值,y没有值,则操作后x,y均没有值
3.x没有值,y有值,则操作后x,y均没有值
那么对于这三种情况我们要特别注意第二条
考虑周全后,代码实现就很简单了
#include<bits/stdc++.h>
using namespace std;
int sum=0;
int f[220];
int main()
{
freopen("evaluate1.in","r",stdin);
freopen("evaluate1.out","w",stdout);
f[97]=1;
char a,b,c;
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a>>b>>c;
if(f[int(c)]==1) f[int(a)]=1;
if(f[int(c)]!=1) f[int(a)]=0;
}
for(int i=97;i<=120;i++)
{
if(f[i]==1)
{
sum++;
if(sum==1) cout<<char(i);
else cout<<' '<<char(i);
}
}
if(sum==0) cout<<"none"<<endl;
return 0;
}
ps:yyx太强了!
三.今日小结
集训第一天,总体来说比较轻松拉~