动态规划的小总结:以pku1050/pku1083/pku1661为例

来源:互联网 发布:ios编程app 编辑:程序博客网 时间:2024/04/30 03:29

以前我发现自己对于动态规划这一技术思想,总是感觉难于运用!然而但我在学习近3个月的理论学习与
用pku实践中,我渐渐发现动态规划其实不难!关键是自己在做题的过程中,找到该题的最忧子结构,然

后在对其进行递归,那么正道题目就将很容易就解决到咯!
现在我就举出自己做的三道动态规划题目进行说明:
1、pku_1050_To_The_Max:

#include "stdio.h"
#include "stdlib.h"

#define N 100

int maxArray(int n, int a[])
{
 int i;
 int b;
 int sum;

 b = 0;
 sum = -10000000;
 
 //在一位数组中进行筛选
 for (i = 0; i < n; i++)
    {
  //首先用b来选择,遇到小于0则放弃
  if (b > 0)
  {
   b += a[i];
  }
  else
  {
   b = a[i];
  }
  //符合要求的,则+
  if (b > sum)
  {
   sum = b;
  }
    }

 return sum;
}

int maxMatrix(int n, int a[N][N])
{
 int i;
 int j;
 int k;
 int max = 0;
 int sum = -100000000;                          //定义其最大值为去穷小
 
 int b[N];
 
 for (i = 0; i < n; i++)
 {
  for (k = 0; k < n; k++)                    //初始化*b
  {
   b[k] = 0;
  }

  for (j = i; j < n; j++)                     //把第i行到第j行相加,对每一次相

加求出最大值
  {
   for (k = 0; k < n; k++)
   {
    b[k] += a[j][k];        //最优子结构
   }

   max = maxArray(k, b);    //在一位数组中寻找最大值

   //在二维中寻找最大值
   if (max > sum)
   {
    sum = max;
   }
  }
    }

    return sum;
}

int main()
{
 freopen("1.txt", "r", stdin);
 int a[N][N];
 int n;
 int i;
 int j;
 int sum = 0;

 scanf("%d",&n);
 for (i = 0; i < n; i++)
 {
  for (j = 0; j < n; j++)
  {
   scanf("%d",&a[i][j]);
  }
 }

 sum = maxMatrix(n, a);
 printf("%d/n",sum);

 return 0;
}
2、pku_1083_Moving_Tables

//标记所有区间,重复记录的就+1
#include "stdio.h"
#include "string.h"
#include "stdlib.h"

int main()
{
 freopen("1.txt","r",stdin);
 int a[401];
 int i, j;
 int p, q;
 int temp;
 int t, n;
 int max;

 scanf("%d",&t);
 while (t--)
 {
  max = -1;                                //定义无穷小
  memset(a, 0, sizeof(a));                 //记录区间
  scanf("%d", &n);

  for(i = 0; i < n; i++)
  {
   scanf("%d%d", &p, &q);
   if (p > q)
   {
    temp = p;
    p = q;
    q = temp;
   }
   p = p - (p + 1) % 2;                //考虑到数组为0号开始
   q = q + (q % 2);
   
   for (j = p; j <= q; j++)
   {
    //用a[j]来记录,1表示有了约定,>1表示重复
    a[j]++;
    if (max < a[j])
    {
     max = a[j];
    }
   }
  }
  max *= 10;
  printf("%d/n", max);
 }
 
 return 0;
}
3、pku_1664_Help_Jimmy

//给每块板加一个LEFT,RIGHT标志,标志它们左右边是否可以落到一块板上,问题就解决了
//f[i][0]:表示到达第i块板左边的最短时间;
//f[i][1]:表示到达第i块板右边的最短时间;

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

const int inf = 0x7fffffff;  //得到的最大随机数为0x7fffffff

struct Board
{
    int high;
    int left;
    int right;
};
Board board[1005];

//按高度从大到小排序
int cmp(const void *a,const void *b)
{
    return (*(Board *)b).high - (*(Board *)a).high;;
}

int min(int a,int b)
{
 return a > b ? b : a;
}

int main()
{
 freopen("1.txt", "r", stdin);

    int i, j, t, N, X, Y, MAX, ans;
    int f[1005][2];
    int LEFT, RIGHT;

    scanf("%d", &t);;
    while(t--)
    {
        scanf("%d%d%d%d", &N, &X, &Y, &MAX);
  ans = inf;
        board[0].left = board[0].right = X;
  board[0].high = Y;
  f[0][0] = f[0][1] = 0;
        for (i = 1; i <= N; i++)
        {
            scanf("%d%d%d", &board[i].left, &board[i].right, &board[i].high);
            f[i][0] = f[i][1] = inf;
        }
        qsort(board, N + 1, sizeof(board[0]), cmp);
        for (i = 0; i <= N; i++)
        {
            if (f[i][0] == f[i][1] && f[i][0] == inf)
   {
    continue;
   }
   LEFT = RIGHT = 0;
            for (j = i + 1; j <= N && board[i].high - board[j].high <= MAX
    && !(LEFT && RIGHT); j++)              //在可以掉下的范围内

进行DP
            {
                if (board[i].left >= board[j].left && board[i].left <= board[j].right && !

LEFT)
     //如果左边可以掉下
                {
                     f[j][0] = min(f[j][0], f[i][0] + board[i].left - board[j].left);
                     f[j][1] = min(f[j][1], f[i][0] + board[j].right - board[i].left);
                     LEFT = 1;
                }
                if (board[i].right >= board[j].left && board[i].right <= board[j].right &&

!RIGHT)
     //如果右边可以掉下
                {
                     f[j][0] = min(f[j][0], f[i][1] + board[i].right - board[j].left);
                     f[j][1] = min(f[j][1], f[i][1] + board[j].right - board[i].right);
                     RIGHT = 1;
                }
            }

   //如果可以直接从左边掉在地上
            if (board[i].high <= MAX && !LEFT)
   {
    ans = min(ans, f[i][0]);
   }
   //如果可以直接从右边掉在地上
            if (board[i].high <= MAX && !RIGHT)
   {
    ans = min(ans, f[i][1]);
   }
        }
        printf("%d/n", ans + Y);
    }
    return 0;
}

原创粉丝点击