动态规划与模拟

编程题

感悟:由于题目写的太水,反思.....

1.倒序打印三角形

在这里插入图片描述

我的通过代码:
总体思路是找到第一个打印的数与n的关系(first=n*(n+1)/2)。第一行最多有n个数
,之后n--,找一个数保存最大列,然后答案印完一行,列数就减一。
#include <stdio.h>
#define N 100
int main () {
	int n,row,col,i,j,a[N][N];
	scanf("%d",&row);
	col=row;
	for(i=1;i<=row;i++) {
			n = col*(col+1)/2;
		for(j=1;j<=col;j++) {
			if(j==col) printf("%d\n",n);
			else printf("%d ",n);
			n--;	
		}
		col--;
	}
	return 0;
}
缺点:虽然容易想到吧,但是执行时间太长....

这不,找到了个执行时间短一点的,注意列可以与行产生“关系”!代码如下:
#include <iostream>
using namespace std;
int main () {
	int n,i,j,sum;
	cin >> n;
	sum = n*(n+1)/2;	//第一个打印的数
	for(i=0;i<n;i++)	//控制行
	{
		for(j=n-i;j>0;j--) //j=n-i,就动态的把列数给减小了,简直不要太nice
		{
			cout << sum;
			if(j>1) cout << " ";
			sum--;	
		} 
		cout << endl;
	} 
	return 0;
}

2.棋盘走法

题目描述:
在这里插入图片描述
在这里插入图片描述

 图片往往令人浮想联翩....
 
 答题思路:动态规划
 
 先将第一行的值赋为1,因为只能向下或者向右,所以从(0,0)开始到第一行,
 只能有一种走法。(每个数组里面的值代表着走法)右下角的格子的走法等于其
 左边的走法加上其上边的走法。即:	a[i][j]=a[i-1][j]+a[i][j-1];

代码如下:

#include <iostream> 
#include <cstdio>
#define N 400
using namespace std;
int main () {
	int a[N][N],i,j,n;
	cin >> n;
	for(i=0;i<n;i++) {
		a[0][i]=1;
	}
	for(i=1;i<n;i++) {			//注意i=1
		for(j=i;j<n;j++) {			//j=i
			a[i][j]=a[i-1][j]+a[i][j-1];
		}
	}
	cout << a[n-1][n-1];
	return 0;
}

3.瓶盖换汽水

在这里插入图片描述在这里插入图片描述

 注意  :重要的是先理清一种情况下的最大可乐数,那个sum函数里面的while循环
 要好好的理清楚,参数比较多,脑壳子不清醒的话就绕进去了.....

代码如下:

#include <iostream>
#include <algorithm>
using namespace std;
int n,x,y;
//本函数只解决一种情况下,即a瓶普通可乐,b瓶青柠可乐,最终能喝到的可乐数 
int sum(int a,int b) {	//普通可乐a瓶,青柠可乐b瓶 
	int ans=n;	//刚开始买了 n瓶
	int coke1,coke2;
	while(a>=x || b>=y){
	
		coke1 = a/x;		
		//该普通可乐a瓶的a个瓶盖最多能换coke1瓶青柠味的可乐 
		coke2 = b/y;
		
		ans += coke1+coke2;
		
		a = a%x + coke2;
		//a%x是剩下未用的瓶盖,加上第一次换了之后的普通可乐(有coke2瓶)的瓶盖 
		b = b%y + coke1; 
	}	
	 return ans;
}
int solve() {
	cin >> n >> x >> y;
	int ans = 0;
	for(int i=0;i<=n;i++) {
		ans = max(ans,sum(i,n-i));	
		//sum(i,n-i)即i瓶普通,n-i瓶青柠,用一个循环找到所有可能中的最大值 
	}
	cout << ans << endl; 
} 
int main () {
	int times;
	cin >> times;	//有times组测试
	while(times--) {
		solve();
	} 
	return 0;
}

4.蛇形矩阵

在这里插入图片描述
在这里插入图片描述
挺蛇形的

 这种题还用说,肯定是擅长的找规律题,但是我看一个真的看不出规律来。。。
 
 考点:模拟
 
 感想:自己没写出来也就算了,看别的题解,上来就是一个速读,哇,真恐怖...

先复制粘贴一波:

   核心仍然在for循环里面,感觉十分巧妙的利用了x和y
#include <bits/stdc++.h>
#pragma GCC optimize(3,"Ofast","inline")
#define re register
#define ll long long
#define ull unsigned long long
#define r read()
using namespace std;
//速读
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
int mp[105][105];
int cnt = 0;
int main()
{
    ios::sync_with_stdio(false);
    int n = r;
    //上三角
    for(int i =  1;i <= n; i++){
        if(i % 2){
            for(int x = 1, y = i; x <= i && y >= 1; x++, y--){
                mp[x][y] = ++cnt;
            }
        }else{
            for(int y = 1, x = i; y <= i && x >= 1; y++, x--){
                mp[x][y] = ++cnt;
            }
        }
    }
    for(int i = n-1;i >= 1; i--){
        if(i % 2){
            for(int x = n - i + 1, y = n; x <= n; x++, y--){
                mp[x][y] = ++cnt;
            }
        }else{
            for(int y = n - i + 1, x = n; y <= n; y++, x--){
                mp[x][y] = ++cnt;
            }
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            cout<<mp[j][i];
            if(j != n){
                cout<<" ";
            }
        }
        cout<<endl;
    }
    return 0;
}

接下来第二种上代码:

#include <iostream>
#include <cstdio>
using namespace std;
int a[200][200];
int main () {
	int n,num=1,flag=0;
	cin >> n;
	//先打印上三角 
	for (int i=1;i<=n;i++) {
		if(flag==0) {
			for(int j=1;j<=i;j++) {
				a[i-j+1][j] = num++;
			}
			flag = 1;  
		} 
		else {
			for(int j=1;j<=i;j++) {
				a[j][i-j+1] = num++;
			}
			flag = 0; 
		}
	}
	for(int i=n+1;i<2*n;i++) {
		int t = 2*n-i;
		if (flag==0) {
			for (int j=i-n+1;j<i-n+1+t;j++){
				a[i-j+1][j]=num++;
			}
			flag = 1;
		}
		else {
			for (int j=i-n+1;j<i-n+1+t;j++){
				a[j][i-j+1]=num++;
			}
			flag = 0;
		}
	} 
	for(int i=1;i<n;i++) {
		for (int j=1;j<n;j++)
			printf("%d ",a[i][j]);
		printf("%d\n",a[i][n]);
	}
	for(int j=1;j<n;j++) {
		printf("%d ",a[n][j]);
	}
	printf("%d",a[n][n]);
	return 0;
}
	我们注意到是以中间的对角线为分隔线开始打印,

还有一种解法(C语言),这个好理解:

#include <stdio.h>
int main () {
	int n,N,i,j,k=0,a[100][100];
	scanf("%d",&n);
	N=1;	//以1 开始打印
	int m=2*(n-1);	//最后一行行和列相加等于2*(n-1) 
	for(k=0;k<=m;k++) {
		if(k%2==0 && k<n) {	//k<n即左上三角 
			for(i=0;i<=k;i++,N++)
				a[k-i][i]=N;		//k+i + i = k, 
		}
		else if (k%2==1 && k<n) {
			for(i=0;i<=k;i++,N++)
				a[i][k-i]=N;
		}
		else if (k%2==0 && k>=n) {
			for(i=n-1;i>k-n;i--,N++)
				a[i][k-i]=N;
		}
		else if (k%2==1 && k>=n) {
			for(i=n-1; i>k-n; i--,N++)
				a[k-i][i]=N;
		} 
	}
	for(i=0;i<n;i++) {
		for(j=0;j<n;j++){
			printf("%d",a[i][j]);
			if(j<n-1) printf(" ");
		}
		printf("\n");
	} 
	return 0;
}

5.传球游戏

在这里插入图片描述

    动态规划,很显然我还不是很了解下面的代码是啥意思...待我学成归来在回顾这一题
#include <bits/stdc++.h>
#pragma GCC optimize(3,"Ofast","inline")
#define re register
#define ll long long
#define ull unsigned long long
#define r read()
using namespace std;
//速读
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
ull dp[999][2];
int main()
{
    ios::sync_with_stdio(false);
    int n = r;
    dp[1][0] = 3;
    for(int i = 2; i <= n; i++){
        dp[i][1] = dp[i-1][0];
        dp[i][0] = dp[i-1][0] * 2 + dp[i-1][1] * 3;
    }
    cout<<dp[n][1];
    return 0;
}

6.分糖果

在这里插入图片描述
在这里插入图片描述
思路:

   我:刚开始想到的是分为两个数组,一个数组里面放输入的数,另一个放应该输
   出的。先让第二个数组里面全为1,即保证每个人分到一个糖果,然后在遍历,如
   果前面的数大于后面的,则相应的数组里面加一,但是只能保证一轮里面只有1和
   2,能过简单的样例,没有考虑到还有会三个糖的,所以遍历一遍远远不够,然后
   开始跑偏,写不出来了...时间截止了...
   
   大佬:将前面一个的糖果和后面一个的糖果联系起来。
#include <bits/stdc++.h>
#pragma GCC optimize(3,"Ofast","inline")
#define re register
#define ll long long
#define ull unsigned long long
#define r read()
using namespace std;
//速读
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
int s[10000];
int cnt[10000];
ll ans = 0;
int main()
{
    ios::sync_with_stdio(false);
    int n = r;
    for(int i = 1; i <= n;i++){
        s[i] = r;		//每个人的评分
        cnt[i] = 1;		//每个人至少一个糖果
    }
    for(int i = 2; i <= n; i++){
        if(s[i]-s[i-1]> 0){ 	//如果右边的比左边大,则右边的糖果比左边的糖果多一个
            cnt[i] = cnt[i-1] + 1;
        }
    }
    for(int i = n; i >= 2; i--){
    //从右往左循环一次,如果左边比右边大,则左边比右边要多一个糖果

        if(s[i]-s[i-1] < 0){
            if(cnt[i] >= cnt[i-1]){
                cnt[i-1] = cnt[i] + 1;
            }
        }
    }
    for(int i = 1;i <= n; i++){			//把所有糖果加起来
        ans += cnt[i];
    }
    cout<<ans<<endl;
    for(int i = 1; i <= n; i++){
        cout<<cnt[i];
        if(i != n){
            cout<<" ";
        }
    }
    return 0;
}
关于第二个for循环:
for example:输入5个人的评分为:1 4 7 2 1,
第一个for循环分到的结果为:1 2 3 1 1,但显然评分为2的那个boy原本要比
最后一个小伙子分到的多,但是由于他比左边的要小,所以并不能加糖果,于是
聪明的我,又从后面来了一次遍历,把boy的糖果给补上了,才能得到最终的结果。

笔试题

(还在反思ing)

网页题

 写的心碎。。。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值