洛谷P1216 数字三角形 Number Triangles
题目描述
观察下面的数字金字塔。
写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
在上面的样例中,从 7→3→8→7→5 的路径产生了最大
输入格式
第一个行一个正整数 r,表示行的数目。
后面每行为这个数字金字塔特定行包含的整数。
输出格式
单独的一行,包含那个可能得到的最大的和。
输入输出样例
输入
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
输出
30
说明/提示
【数据范围】
对于 100% 的数据,1≤r≤1000,所有输入在 [0,100]范围内。
代码
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int M = 1005;
int r;
int dp[M][M],a[M][M];
int dfs(int i,int j)
{
if(i==r) return a[i][j];
if(dp[i][j]>=0) return dp[i][j];
return dp[i][j]=max(dfs(i+1,j),dfs(i+1,j+1))+a[i][j];
}
int main()
{
memset(dp,-1,sizeof(dp));
memset(a,0,sizeof(a));
cin>>r;
for(int i=1;i<=r;i++){
for(int j=1;j<=i;j++){
scanf("%d",&a[i][j]);
}
}
printf("%d\n",dfs(1,1));
return 0;
}
洛谷P1434 [SHOI2002]滑雪
题目描述
Michael 喜欢滑雪。这并不奇怪,因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。Michael 想知道在一个区域中最长的滑坡。区域由一个二维数组给出。数组的每个数字代表点的高度。下面是一个例子:
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度会减小。在上面的例子中,一条可行的滑坡为 24-17-16-1(从 24 开始,在 1 结束)。当然 25-24-23-…-3-2-1 更长。事实上,这是最长的一条。
输入格式
输入的第一行为表示区域的二维数组的行数 RR 和列数 CC。下面是 RR 行,每行有 CC 个数,代表高度(两个数字之间用 11 个空格间隔)。
输出格式
输出区域中最长滑坡的长度。
输入输出样例
输入
5 5
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
输出
25
说明/提示
对于 100% 的数据,1≤R,C≤100。
代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100+5;
int r,c;
int h[N][N];
int dp[N][N];
int dir[4][2]={
{1,0},
{0,1},
{-1,0},
{0,-1}
};
int dfs(int x,int y)
{
if(dp[x][y]!=0) return dp[x][y];
int maxt=1;
int t;
for(int i=0;i<4;i++){
int nx=x+dir[i][0];
int ny=y+dir[i][1];
if(nx>0&&ny>0&&nx<=r&&ny<=c&&h[nx][ny]>h[x][y]){
t=dfs(nx,ny)+1;
maxt=max(t,maxt);
}
}
dp[x][y]=maxt;
return maxt;
}
int main()
{
int ans=0;
memset(dp,0,sizeof(dp));
scanf("%d%d",&r,&c);
for(int i=1;i<=r;i++){
for(int j=1;j<=c;j++){
scanf("%d",&h[i][j]);
}
}
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++){
dp[i][j]=dfs(i,j);
ans=max(ans,dp[i][j]);
}
printf("%d\n",ans);
return 0;
}
洛谷P1464 Function
题目描述
输入输出格式
输入输出样例
输入
1 1 1
2 2 2
-1 -1 -1
输出
w(1, 1, 1) = 2
w(2, 2, 2) = 4
代码
#include<iostream>
#include<cstring>
using namespace std;
const int N = 25;
int f[N][N][N];
int dfs(int a,int b,int c)
{
if(a<=0||b<=0||c<=0) return 1;
if(a>20||b>20||c>20) return dfs(20,20,20);
if(f[a][b][c]) return f[a][b][c];
if(a<b&&b<c) f[a][b][c] = dfs(a,b,c-1)+dfs(a,b-1,c-1)-dfs(a,b-1,c);
else f[a][b][c] = dfs(a-1,b,c)+dfs(a-1,b-1,c)+dfs(a-1,b,c-1)-dfs(a-1,b-1,c-1);
return f[a][b][c];
}
int main()
{
int x,y,z;
//freopen("data.txt","r",stdin);
while(~scanf("%d %d %d",&x,&y,&z)){
if(x==-1&&y==-1&&z==-1) break;
memset(f,0,sizeof(f));
printf("w(%d, %d, %d) = %d\n",x,y,z,dfs(x,y,z));
}
return 0;
}
洛谷 P2690 [USACO04NOV]Apple Catching G
输入格式
第一行2个数,T和W。接下来的t行,每行一个数,代表在时刻t苹果是从1号苹果树还是从2号苹果树上掉下来的。
输出格式
对于每个测试点,输出一行,一个数,为奶牛最多接到的苹果的数量。
输入输出样例
输入
7 2
2
1
1
2
2
1
1
输出
6
#include<iostream>
#include<cstring>
using namespace std;
int n,w,a[1005];
int f[1005][3][35];
int dfs(int i,int j,int k)//i为时间点,j为哪棵树,k为移动了多少次
{
if(i>n) return 0;
if(f[i][j][k]!=-1) return f[i][j][k];
int t1=0,t2=0;
if(k<w&&a[i]!=j)
t1=dfs(i+1,-1*j+3,k+1)+1;
t2=dfs(i+1,j,k)+(j==a[i]?1:0);
return f[i][j][k]=max(t1,t2);
}
int main()
{
//freopen("data.txt","r",stdin);
scanf("%d %d",&n,&w);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
memset(f,-1,sizeof(f));
printf("%d\n",dfs(1,1,0));
return 0;
}
题目描述
(良心出题人wzc说这是个简单拓扑dp,它就必然是一个简单拓扑dp,wzc是不会骗人的)
wzc在一张拓扑图上,他所在的起始位置被标记为0。除了起始位置外,还有被1到n这n个整数所标记的n个顶点,每个顶点i都有一个正整数值xi。
这些顶点之间存在着m条有向边。题目保证图中不存在环,且从顶点0出发必定能到达顶点n。
wzc希望从起点0出发经过某条路径到达顶点n,并且收集经过的所有结点上的数字,使得所有数字的和最大。
现在请你帮wzc求出他能得到的最大数字和是多少。
输入描述:
第一行包含两个整数n,m(1<=n<=1e5,1<=m<=min(n*(n+1)/2,2e5))表示除了起点外的顶点的个数,以及有向边的条数。
第二行为n个空格隔开的整数xi,分别代表顶点1,顶点2,…顶点n上的数字。(1<=xi<=1000)
接下来m行,每行两个整数a,b(0<=a,b<=n),代表有一条有向边从顶点a指向顶点b。
输出描述:
输出一个整数,表示wzc能得到的最大数字和是多少。
示例1
输入
5 6
9 5 8 7 4
0 4
2 1
1 5
3 5
4 3
4 2
输出
25
代码
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxm=1e5+5;
int num[maxm];
int dp[maxm];
vector<vector<int>> edge;
int ans=0;
int dfs(int now,int target,int cost)
{
if(now==target)
{
ans=max(ans,cost);
// cout<<ans<<endl;
return cost;
}
else if(dp[now]!=-1)
{
return dp[now]+cost;
}
for(int i=0;i<edge[now].size();i++)
{
dp[now]=max(dp[now],dfs(edge[now][i],target,cost+num[edge[now][i]]));
}
return dp[now];
}
int main()
{
memset(dp,-1,sizeof(dp));
num[0]=0;
int n,m,x,y;
cin>>n>>m;
edge.resize(n+1);
for(int i=1;i<=n;i++)cin>>num[i];
for(int i=0;i<m;i++)
{
cin>>x>>y;
edge[x].push_back(y);
}
dfs(0,n,0);
cout<<ans<<endl;
return 0;
}