P1434 [SHOI2002]滑雪+最近各种自选dp小题

题目请自行搜索,来源于各个oj平台。

P1434 [SHOI2002]滑雪

标签
各省省选
上海
2002

题目描述
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
一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度会减小。在上面的例子中,一条可行的滑坡为 2424-1717-1616-11(从 2424 开始,在 11 结束)。当然 2525-2424-2323-\ldots…-33-22-11 更长。事实上,这是最长的一条。

输入格式
输入的第一行为表示区域的二维数组的行数 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%100% 的数据,1\leq R,C\leq 1001≤R,C≤100。

//https://www.luogu.com.cn/problem/P1434
/*
	滑雪题,首先这道题无明确终点,
	方法1可以搜索,记得记忆化搜索。

	方法2可以是dp:dp记得排序,然后每次更新dp都是从四个方向,而且四个方向本来就要求
	必须是小于的才可以走,那么更新dp的第一个for从小到大即可,保证最后结果正确
*/
#include<bits/stdc++.h>
using namespace std;
int a[100][100];
int n,m;
int Back_sum;
int dp[100][100];//记录每次的最大值
int way[4][2]= {0,1,1,0,0,-1,-1,0};
void dfs(int i,int j,int sum) {
	if(dp[i][j]!=1) {
		Back_sum = max(Back_sum,sum-1+dp[i][j]);
		return;//关键一步!!!!!!! 
	}
	Back_sum = max(Back_sum,sum);
	for(int k = 0; k < 4; k++) {
		int x = i+way[k][0];
		int y = j+way[k][1];//!!!坐标的位置
		if(x>=0&&y>=0&&x<n&&y<m&&a[x][y]<a[i][j]) {
			dfs(x,y,sum+1);//不接收Back_sum!!
		}
	}
}
int main() {
	scanf("%d%d",&n,&m);
	fill(dp[0],dp[0]+10000,1);
	for(int i = 0; i < n; i++) {
		for(int j = 0; j < m; j++) {
			scanf("%d",&a[i][j]);
		}
	}
	int ans=0;
	for(int i = 0; i < n; i++) {
		for(int j = 0; j < m; j++) {
			Back_sum = 0;
			dfs(i,j,1);
			dp[i][j] = Back_sum;//Back_sum传出来!!!
			ans = max(ans,dp[i][j]);
		}
	}
	printf("%d\n",ans);


}

DP解法

#include<iostream>
#include<cstdio> 
#include<algorithm>
using namespace std;//dp版 
int ii,jj,maxx;
int fx[4][2]={0,1,1,0,0,-1,-1,0};
int a[105][105];
int d[105][105];
struct node
{
    int i;
    int j;
    int x;
}n[10005]; 
int read()
{
    int x=0;
    char ch=getchar();
    while(ch>'9'||ch<'0')
    {
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x;
}
bool cmp(node a,node b)
{
    return a.x<b.x;
}
int main()
{
    freopen("in.txt","r",stdin);
    ii=read();
    jj=read();
    int tt=0;
    for(int i=0;i<ii;i++)
    {
        for(int j=0;j<jj;j++)
        {
            n[tt].i=i;
            n[tt].j=j;
            a[i][j]=read();
            n[tt].x=a[i][j];
            d[i][j]=1;
            tt++;
        }
    }
    sort(n,n+tt,cmp);
    for(int t=0;t<tt;t++)
    {
        int i=n[t].i;
        int j=n[t].j;
        for(int k=0;k<4;k++)
        {
            int f=i+fx[k][0];
            int g=j+fx[k][1];
            if(f>=0&&g>=0&&f<ii&&g<jj)
            {
                if(a[f][g]<a[i][j])
                {
                    d[i][j]=max(d[i][j],d[f][g]+1);
                }
            }
        }
        maxx=max(maxx,d[i][j]);
    }
    printf("%d",maxx);
    return 0;
}

简易版之最短距离

#include<iostream>
#include<cmath>
using namespace std;
int a[600];
#define maxx INFINITY
int main() {
	int N;
	scanf("%d",&N);
	int maxans = 0;
	int ans = 0;
	while(N--) {
		int minn = 1e+9;

		int M;
		scanf("%d",&M);
		for(int i = 0; i < M; i++) {
			scanf("%d",&a[i]);
		}
		for(int i = 0; i < M; i++) {
			maxans = 0;
			for(int j = 0; j < M; j++) {
				maxans += abs(a[i]-a[j]);
			}
			if(maxans<minn) {
				minn = maxans;
			}
		}
		printf("%d\n",minn);
	}

}

打家劫舍

class Solution {
public:
    int rob(vector<int>& nums) {
        int len = nums.size();
        if(len == 0) return 0;
        if(len ==1 ) return nums[0];
        int dp[100];
        dp[0] = nums[0];
        dp[1] = max(dp[0],nums[1]);
        for(int i = 2;i < nums.size();i++){
            dp[i] = max(dp[i-1],dp[i-2]+nums[i]);
        }
        return dp[nums.size()-1];//!!!!!!!
    }
};

P1025 数的划分

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int N;
int n,k;
int P[1000] = {0};
int total;
int countN;
//没有什么花里胡哨,这题就是按照排列的思想来就行
//万变不离其宗,只不过这里的数,不能从1开始,必须从上一位数开始
//这样的话,也不是组合,很明显了
//需要回忆的是,组合是只能拿与不拿的。
//出现重复,立马考虑排列,假如是组合,记得思考位数
//排列的话,那么只需要判断就行了,如下 
void generate(int index) {
	if(total < 0)
		return;
	if(index == k+1) {
		if(total == 0) {
			countN++;
		}
		return;
	}
	//下次拿只能从自己的上一位的数,大于等于地拿
	//剪枝   n-total代表的是已经加的数之和, 判断剩余的数能否放进去 比如 222行 23就不行 
	for(int i = P[index-1]; (n-total)+i*(k-index+1) <= n; i++) {
		P[index] = i;
		//拿数,即减去
		total -= i;
		if(total < 0){
			total += i;
			continue;
		}
		generate(index+1);
		total += i;
	}
}
int main() {
	scanf("%d%d",&n,&k);
	total = n;
	countN=0;
	P[0] = 1;
	generate(1);
	printf("%d",countN);

}

数塔

扫描二维码关注公众号,回复: 10756365 查看本文章
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int a[110][110];
int main() {
	int N;
	int M;
	scanf("%d",&M);
	while(M--) {
		memset(a,0,sizeof(a));
		scanf("%d",&N);
		for(int i =1; i<=N; i++) {
			for(int j = 1; j <= i; j++) {
				scanf("%d",&a[i][j]);
			}
		}
		int dp[110][110] = {0};
		for(int i =1; i<=N; i++) {
			dp[N][i] = a[N][i];
		}
		for(int i = N -1; i>=1; i--) {
			for(int j = 1; j <= i; j++) {
				dp[i][j] = a[i][j] + max(dp[i+1][j],dp[i+1][j+1]);
			}
		}
		printf("%d\n",dp[1][1]);
	}
}
发布了154 篇原创文章 · 获赞 4 · 访问量 8620

猜你喜欢

转载自blog.csdn.net/weixin_38023259/article/details/105367981
今日推荐