1.洛谷P1006 [NOIP2008 提高组] 传纸条
P1006 [NOIP2008 提高组] 传纸条 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路分析:
该题为经典的dp动态,除了起始点(1,1)和终点(n,m)纸条的来回传递位置不能重复,我们可以把该来回的过程看作是两个纸条从起始点到终点的过程。可以设置一个四位数组(F[r1][c2][r2][c2])来纪录两个点的位置。但是这样需要用四个循环,非常的费时间,可能会超时。所以我们改为三维数组(F[p][r1][r2])来记录,因为每时每刻两个纸条走的步数p相同。i, j分别表示他们处在的行数则他们的坐标分别为(i,p-i+1) (j,p-j+1)。当i和j相等时即两点在同一位置(证明该点的值对上一步的两个纸条来说都比较大(如图))则点的值只能加一次。
代码:
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int f[110][60][60];
int a[60][60];
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> a[i][j];
f[1][1][1] = a[1][1];
for (int p = 2; p <= n + m - 1; p++)
for (int i = 1; i <= n && i <= p; i++)
for (int j = 1; j <= n && j <= p; j++)
{
if (i == 1 && j == 1) continue;
//找出上一步中的最大值
f[p][i][j] = max(max(f[p - 1][i][j], f[p - 1][i - 1][j]), max(f[p - 1][i][j - 1], f[p - 1][i - 1][j - 1]));
// 三目运算符 判断条件?true输出表达式1:false输出表达式2;然后求和
//表达式1即为i和j相等,位置重复则只加一次
f[p][i][j] += i == j ? a[i][p - i + 1] : a[i][p - i + 1] + a[j][p - j + 1];
}
printf("%d\n", f[n + m - 1][n][n]);
return 0;
}
小知识点总结:
三目运算符 判断条件?(true)输出表达式1:(false)输出表达式2;
2.洛谷 P1008 [NOIP1998 普及组] 三连击
P1008 [NOIP1998 普及组] 三连击 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目分析:
将1到9组成三个三位数并且是1比2比3的关系,怎么组怎么比毫无头绪,但是组成的这三个数(假设能重复)各自的范围是100~333:334~666:667~999;不重复则最小的三位数是123,最大的为987,于是我们就有一个大胆的想法,让三个数分别为a,b,c。则可以让a从123开始循环b=2*a;c=3*a;保证abc三个数只能用一次1~9则将百位十位个位分离验证。
知识点:
分离百十个位方法 设该数为n
百位=n%100;
十位=n/10%10;
个位=n%10;
代码:
#include<iostream>
using namespace std;
int main()
{
for (int a=123; a <= 333; a++)
{
int b, c;
b = a * 2;
c = a * 3;
if ((a / 100 + a / 10 % 10 + a % 10 + b / 100 + b / 10 % 10 + b % 10 + c / 100 + c / 10 % 10 + c % 10 == 1+2+3+4+5+6+7+8+9)&&( (a/100)*(a/10%10)*(a%10)*(b/100)*(b/10%10)*(b%10)*(c/100)*(c/10%10)*(c%10)==1*2*3*4*5*6*7*8*9 ) )
cout << a <<" " << b << " " << c << endl;
}
return 0;
}