25.数字三角形
题目描述
有一个由数字组成的三角形数塔,站在上一层的某个点,只能到达其下方左右的两个点。现在请找到一条从上到下的路径,使得路径上所有数字相加之和最大
输入
第一行输入一个数字 n(1≤n≤1000)(1≤n≤1000)代表数塔层数
接下来n行,按数塔图形,每行有一个或多个的整数,表示该层节点的值(节点值≤100000)(节点值≤100000)
输出
输出一个整数,代表从上到下路径上所有数字相加和的最大值。
样例输入1
6
3
9 5
4 2 1
3 4 9 6
3 5 3 7 3
2 1 3 9 3 2
样例输出1
39
数据规模与约定
时间限制:1 s
内存限制:64 M
100% 的数据保证 1≤n≤1000
题解思路
* 本题是经典的动态规划问题:
* 状态:d[i][j]表示从(i,j)出发,能得到的最大和。包括(i,j)
* 那么原问题便转化成了求d[0][0]
* 从(i,j)出发可以向下走(i+1,j),也可以向右下走(i+1,j+1),
* 然后问题就变成了从(i+1,j)或者从(i+1,j+1)出发的最大和
* 于是状态转移方程为:d[i][j] = max(d[i+1][j], d[i+1][j+1]) + a[i][j]
完整代码:
/*************************************************************************
> File Name: 1.triangle.cpp
> Author: 数字三角形
> Mail:
> Created Time: 2021年02月20日 星期六 09时03分01秒
************************************************************************/
#include<iostream>
#include<cstdio>
using namespace std;
#define MAX_NUM 100
int d[MAX_NUM + 10][MAX_NUM + 10];
int N;
int MaxSum(int r,int j) //递归求解最大路径和
{
if(r == N)
return d[r][j];
int sum1 = MaxSum(r + 1, j);
int sum2 = MaxSum(r + 1, j + 1);
if(sum1 > sum2)
return sum1 + d[r][j];
return sum2 + d[r][j];
}
int main()
{
int m;
cin >> N;
for(int i = 1; i <= N; i++)
for(int j = 1; j <= i; j++)
cin >> d[i][j];
cout << MaxSum(1,1);
return 0;
}
26.钓鱼(贪心)
题目描述
有N个鱼塘排成一排(N<100),每个鱼塘中有一定数量的鱼,例如:N=5时,如下表:
鱼塘编号每1分钟能钓到的鱼的数量(1…1000)每1分钟能钓鱼数的减少量(1…100)当前鱼塘到下一个相邻鱼塘需要的时间(单位:分钟)11023214453206441654593鱼塘编号12345每1分钟能钓到的鱼的数量(1…1000)101420169每1分钟能钓鱼数的减少量(1…100)24653当前鱼塘到下一个相邻鱼塘需要的时间(单位:分钟)3544
即:在第1个鱼塘中钓鱼第1分钟内可钓到10条鱼,第2分钟内只能钓到8条鱼,……,第5分钟以后再也钓不到鱼了。从第1个鱼塘到第2个鱼塘需要3分钟,从第2个鱼塘到第3个鱼塘需要5分钟,……
给出一个截止时间T(T<1000),设计一个钓鱼方案,从第1个鱼塘出发,希望能钓到最多的鱼。
假设能钓到鱼的数量仅和已钓鱼的次数有关,且每次钓鱼的时间都是整数分钟。
【输入】
共5行,分别表示:
第1行为N;
第2行为第1分钟各个鱼塘能钓到的鱼的数量,每个数据之间用一空格隔开;
第3行为每过1分钟各个鱼塘钓鱼数的减少量,每个数据之间用一空格隔开;
第4行为当前鱼塘到下一个相邻鱼塘需要的时间;
第5行为截止时间T。
【输出】
一个整数(不超过231−1231−1),表示你的方案能钓到的最多的鱼。
【输入样例】
5
10 14 20 16 9
2 4 6 5 3
3 5 4 4
14
【输出样例】
76
解题思想
问题抽取
- 变量太多了,行走时间,停留时间
- 湖比较少,我们枚举最后停留的湖,把行走时间变成常量
- 问题中以5分钟作为基本单位,不妨把5去掉
- 行走时间为常量,那问题等价为佳佳可以瞬间移动
解题思路:用堆和贪心的方法,先把各项数据读入并存储在数组里面,然后开始枚举最远走到的池塘编号,收集能够钓鱼的池塘的资料,接着把堆初始化,并用贪心选取鱼最多的池塘,最后输出最优解即可。
完整代码:
/*************************************************************************
> File Name: 2.fishing.cpp
> Author: 钓鱼(贪心)
> Mail:
> Created Time: 2021年02月20日 星期六 14时12分01秒
************************************************************************/
#include<iostream>
#include<stdio.h>
using namespace std;
int a[105],b[105],c[105],v[105];
int main()
{ freopen("fishing.in","r",stdin);
freopen("fishing.out","w",stdout);
int n;
cin>>n;
for (int i=1;i<=n;++i)
{ cin>>a[i];
}
for (int i=1;i<=n;++i)
cin>>b[i];
for (int i=1;i<=n-1;++i)
{ cin>>c[i];
c[i]=c[i]+c[i-1];
}
int maxxx=0;
int t;cin>>t;
for (int i=1;i<=n;++i)
{ int s=t;
s=s-c[i-1];
int ans=0;
for (int j=1;j<=i;++j)
v[j]=a[j]+b[j];
for (int j=1;j<=s;++j)
{ int maxx=0,xh,y;
for (int k=1;k<=i;++k)
{ y=v[k]-b[k];
if (y>maxx)
{ maxx=y;
xh=k;
}
}
v[xh]=v[xh]-b[xh];
ans+=maxx;
}
maxxx=max(maxxx,ans);
}
cout<<maxxx;
}
27.墙壁涂色
题目描述
给一个环形的墙壁涂颜色,颜色一共有 k 种,墙壁被竖直地划分成 n 个部分,相邻的部分颜色不能相同。请你写程序计算出一共有多少种给墙壁上色的方案?
例如,当 n=5,k=3n=5,k=3 时,下面是一种合法的涂色方案
而由于墙壁是环形的,所以下面就是一种非法的方案
输入
输入两个数字 n,k(1≤n≤103,2≤k≤10)(1≤n≤103,2≤k≤10),分别代表墙壁数量和颜色种类。
输出
对于每个询问,输出一行整数,合法的墙壁涂色方案数。
样例输入1
5 3
样例输出1
30
数据规模与约定
时间限制:5 s
内存限制:256 M
20% 的数据保证 n≤20,k=3n≤20,k=3
40% 的数据保证 n≤40,k=4n≤40,k=4
80% 的数据保证 n≤40,k≤10n≤40,k≤10
100% 的数据保证 n≤103,k≤10n≤103,k≤10
递推高精度从递推到动归(一)提高组
题目分析
1.假设函数:设f[n]为n个尺寸的墙有几种不同排序
2.递推的本质:用已知推未知:寻找前后项之间的关系,仔细思考n-1和n之间的关系,可以分为两种情况
当第1项和第n-1项不同色时。第n项只有一种颜色可以取,即f[n]=f[n-1]
当第1项和第n-1项同色时。第n项有两种颜色可以取,同时因为第n块和第n-1块不同色,所以f[n]=2*f[n-2]
由高中数学知识,分类相加,不难得到f[n] = f[n-1] + f[n-2]*2 (n>3)
别忘了f[1]=3,f[2]=f[3]=6
完整代码:
/*************************************************************************
> File Name: 3.tintage.cpp
> Author: 墙壁涂色
> Mail:
> Created Time: 2021年02月20日 星期六 23时05分01秒
************************************************************************/
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
const int maxn = 1000;
struct bign{
int d[maxn], len;
void clean() { while( len > 1 && !d[len - 1]) len--; }
bign() {
memset(d, 0, sizeof(d)); len = 1;
}
bign(int num) { *this = num; }
bign(char* num) { *this = num; }
bign operator = (const char* num){
memset(d, 0, sizeof(d));
len = strlen(num);
for(int i = 0; i < len; i++) d[i] = num[len - 1 - i] - '0';
clean();
return *this;
}
bign operator = (int num){
char s[20]; sprintf(s, "%d", num);
*this = s;
return *this;
}
bign operator + (const bign& b){
bign c = *this; int i;
for (i = 0; i < b.len; i++){
c.d[i] += b.d[i];
if (c.d[i] > 9) c.d[i] %= 10, c.d[i + 1]++;
}
while (c.d[i] > 9) c.d[i++] %= 10, c.d[i]++;
c.len = max(len, b.len);
if (c.d[i] && c.len <= i) c.len = i + 1;
return c;
}
bign operator - (const bign& b){
bign c = *this; int i;
for (i = 0; i < b.len; i++){
c.d[i] -= b.d[i];
if (c.d[i] < 0) c.d[i]+=10, c.d[i+1]--;
}
while (c.d[i] < 0) c.d[i++]+=10, c.d[i]--;
c.clean();
return c;
}
bign operator * (const bign& b)const{
int i, j; bign c; c.len = len + b.len;
for(j = 0; j < b.len; j++) for(i = 0; i < len; i++)
c.d[i+j] += d[i] * b.d[j];
for(i = 0; i < c.len-1; i++)
c.d[i+1] += c.d[i]/10, c.d[i] %= 10;
c.clean();
return c;
}
bign operator / (const bign& b){
int i, j;
bign c = *this, a = 0;
for (i = len - 1; i >= 0; i--)
{
a = a*10 + d[i];
for (j = 0; j < 10; j++) if (a < b*(j+1)) break;
c.d[i] = j;
a = a - b*j;
}
c.clean();
return c;
}
bign operator % (const bign& b){
int i, j;
bign a = 0;
for (i = len - 1; i >= 0; i--)
{
a = a*10 + d[i];
for (j = 0; j < 10; j++) if (a < b*(j+1)) break;
a = a - b*j;
}
return a;
}
bign operator += (const bign& b){
*this = *this + b;
return *this;
}
bool operator <(const bign& b) const{
if(len != b.len) return len < b.len;
for(int i = len - 1; i >= 0; i--)
if(d[i] != b.d[i]) return d[i] < b.d[i];
return false;
}
bool operator >(const bign& b) const{return b < *this;}
bool operator<=(const bign& b) const{return !(b < *this);}
bool operator>=(const bign& b) const{return !(*this < b);}
bool operator!=(const bign& b) const{return b < *this || *this < b;}
bool operator==(const bign& b) const{return !(b < *this) && !(b > *this);}
string str() const{
char s[maxn] = {};
for(int i = 0; i < len; i++) s[len - 1 - i] = d[i] + '0';
return s;
}
};
istream& operator >> (istream& in, bign& x)
{
string s;
in >> s;
x = s.c_str();
return in;
}
ostream& operator << (ostream& out, const bign& x)
{
out << x.str();
return out;
}
int main()
{
bign ans;
ans = 1;
int n, m; cin >> n >> m;
bign nn,mm;
nn = n;
mm = m;
if(n % 2 == 0){
for(int i = 1; i <= n; i++)
ans = ans * (mm - 1);
ans = ans + mm - 1;
}
else{
for(int i = 1; i <= n; i++)
ans = ans * (mm - 1);
ans = ans - mm + 1;
}
cout << ans << endl;
return 0;
}