动态规划与模拟

简介: 我的通过代码:总体思路是找到第一个打印的数与n的关系(first=n*(n+1)/2)。第一行最多有n个数,之后n--,找一个数保存最大列,然后答案印完一行,列数就减一。

动态规划与模拟


月考核总结

  • 1.倒序打印三角形
  • 2.棋盘走法
  • 3.瓶盖换汽水
  • 4.蛇形矩阵
  • 5.传球游戏
  • 6.分糖果


1.倒序打印三角形


1.png

我的通过代码:
总体思路是找到第一个打印的数与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.png

1.png

先将第一行的值赋为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.瓶盖换汽水


1.png

1.png

1.png

代码如下:

注意  :重要的是先理清一种情况下的最大可乐数,那个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.蛇形矩阵


1.png

1.png

1.png


先复制粘贴一波:

核心仍然在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.传球游戏


1.png

动态规划,很显然我还不是很了解下面的代码是啥意思...待我学成归来在回顾这一题
#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.png

1.png

思路:

 刚开始想到的是分为两个数组,一个数组里面放输入的数,另一个放应该输
 出的。先让第二个数组里面全为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的糖果给补上了,才能得到最终的结果。


相关文章
|
7月前
|
算法 测试技术 C#
【动态规划】1223. 掷骰子模拟
【动态规划】1223. 掷骰子模拟
|
7月前
|
算法
动态规划的思路
动态规划的思路
|
7月前
|
算法
动态规划求解超详细介绍 例题+代码
动态规划求解超详细介绍 例题+代码
|
7月前
|
存储 算法
算法思想总结:模拟算法
算法思想总结:模拟算法
|
7月前
|
算法 测试技术 C#
利用广度优先或模拟解决米诺骨牌
利用广度优先或模拟解决米诺骨牌
|
7月前
|
存储 缓存 算法
【算法训练-动态规划 零】动态规划解题框架
【算法训练-动态规划 零】动态规划解题框架
106 0
|
决策智能 索引 Python
动态规划原理及案例介绍
更多文章可关注我的微信公众号:python学习杂记
267 0
|
存储 人工智能 算法
【算法分析与设计】动态规划(上)
【算法分析与设计】动态规划(上)
|
算法
贪心算法的思路和典型例题
贪心算法的思路和典型例题