zoukankan      html  css  js  c++  java
  • 18.5.24 动规作业

    A:UNIMODAL PALINDROMIC DECOMPOSITIONS

    描述

    A sequence of positive integers is Palindromic if it reads the same forward and backward. For example:
    23 11 15 1 37 37 1 15 11 23
    1 1 2 3 4 7 7 10 7 7 4 3 2 1 1
    A Palindromic sequence is Unimodal Palindromic if the values do not decrease up to the middle value and then (since the sequence is palindromic) do not increase from the middle to the end For example, the first example sequence above is NOT Unimodal Palindromic while the second example is.
    A Unimodal Palindromic sequence is a Unimodal Palindromic Decomposition of an integer N, if the sum of the integers in the sequence is N. For example, all of the Unimodal Palindromic Decompositions of the first few integers are given below:
    1: (1)
    2: (2), (1 1)
    3: (3), (1 1 1)
    4: (4), (1 2 1), (2 2), (1 1 1 1)
    5: (5), (1 3 1), (1 1 1 1 1)
    6: (6), (1 4 1), (2 2 2), (1 1 2 1 1), (3 3),
    (1 2 2 1), ( 1 1 1 1 1 1)
    7: (7), (1 5 1), (2 3 2), (1 1 3 1 1), (1 1 1 1 1 1 1)
    8: (8), (1 6 1), (2 4 2), (1 1 4 1 1), (1 2 2 2 1),
    (1 1 1 2 1 1 1), ( 4 4), (1 3 3 1), (2 2 2 2),
    (1 1 2 2 1 1), (1 1 1 1 1 1 1 1)

    Write a program, which computes the number of Unimodal Palindromic Decompositions of an integer.

    输入Input consists of a sequence of positive integers, one per line ending with a 0 (zero) indicating the end.输出For each input value except the last, the output is a line containing the input value followed by a space, then the number of Unimodal Palindromic Decompositions of the input value. See the example on the next page.样例输入

    2
    3
    4
    5
    6
    7
    8
    10
    23
    24
    131
    213
    92
    0

    样例输出

    2 2
    3 2
    4 4
    5 3
    6 7
    7 5
    8 11
    10 17
    23 104
    24 199
    131 5010688
    213 1055852590
    92 331143

    提示

    N < 250

    来源G

    reater New York 2002

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <string.h>
     4 #include <algorithm>
     5 #include <stdlib.h>
     6 #include <math.h>
     7 
     8 using namespace std;
     9 
    10 const int maxn = 255;
    11 unsigned dp[maxn][maxn];
    12 int n, maxnow;
    13 
    14 void dpsolve() {
    15     for (int i = maxnow+1; i <= n; i++)
    16     {
    17         for (int plus=i/2;plus>=1;plus--)
    18         {
    19             dp[i][plus] = dp[i-2*plus][plus]+dp[i][plus+1];
    20         }
    21     }
    22     maxnow = n;
    23     printf("%d %u
    ", n, dp[n][1]);
    24 }
    25 
    26 void init() {
    27     maxnow = 1;
    28     for (int i = 0; i < maxn; i++)dp[0][i] = 1;
    29     for (int i = 1; i < maxn; i++)
    30         for (int j = 0; j < maxn; j++)dp[i][j] = bool(j <= i);
    31     while (~scanf("%d", &n) && n) {
    32         if (n <= maxnow)printf("%d %u
    ",n, dp[n][1]);
    33         else
    34             dpsolve();
    35     }
    36 }
    37 
    38 
    39 int main()
    40 {
    41     init();
    42     return 0;
    43 }
    View Code

    解题思路

    拆分所需要的数,如8=2+4+2,则在总和为4的回文串的基础之上,可以在两端加上2组成一个新的总和为8的回文串,这种情况的种数就是和为4并且最小数大于2的回文串的种数。

    下午脑子不太清楚,晕了很长时间,一开始还以为是拆分成两边各一个,后来突然发现——我踏马在写啥……重写了两三次,没理解清晰题意

    B:滑雪

    描述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。当然25-24-23-...-3-2-1更长。事实上,这是最长的一条。输入输入的第一行表示区域的行数R和列数C(1 <= R,C <= 100)。下面是R行,每行有C个整数,代表高度h,0<=h<=10000。输出输出最长区域的长度。样例输入

    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

    来源

    Don't know

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <string.h>
     4 #include <algorithm>
     5 #include <stdlib.h>
     6 #include <math.h>
     7 
     8 using namespace std;
     9 
    10 const int maxn = 105;
    11 int r, c, sum=1, maxlen=1;
    12 int dp[maxn][maxn],area[maxn][maxn];
    13 int dirr[4] = { 0,0,-1,1 }, dirl[4] = { -1,1,0,0 };
    14 
    15 struct node {
    16     int x, y;
    17     int high;
    18 }map[maxn*maxn];
    19 bool cmp(node&a1,node&a2){
    20     return a1.high<a2.high;
    21 }
    22 
    23 void init() {
    24     scanf("%d%d", &r, &c);
    25     for (int i = 1; i <= r; i++)
    26         for (int j = 1; j <= c; j++)
    27         {
    28             scanf("%d", &map[sum].high);
    29             map[sum].x=i,map[sum].y=j;
    30             area[i][j]=map[sum].high;
    31             dp[i][j]=1;
    32             sum++;
    33         }
    34     sum--;
    35     sort(map+1,map+r*c+1,cmp);
    36 }
    37 
    38 void dpsolve(){
    39     for(int i=0;i<sum;i++)
    40         for(int j=0;j<=3;j++)
    41         {
    42             if(area[map[i].x+dirr[j]][map[i].y+dirl[j]]>area[map[i].x][map[i].y])
    43             {
    44                 dp[map[i].x+dirr[j]][map[i].y+dirl[j]]=max(dp[map[i].x+dirr[j]][map[i].y+dirl[j]],dp[map[i].x][map[i].y]+1);
    45                 maxlen=max(maxlen,dp[map[i].x+dirr[j]][map[i].y+dirl[j]]);
    46             }
    47         }
    48     printf("%d",maxlen);
    49 }
    50 
    51 int main()
    52 {
    53     init();
    54     dpsolve();
    55     return 0;
    56 }
    View Code

    熟悉的题目……把顺治换成了Michael

    解题思路

    将点按高度从小到大排好(我是从小到大划路线的),然后看四周有没有点比它高,高的话就把那个点的dp状态加一( dp[x][y] 指这个点出发的最长路径)

    C:硬币

    描述

    宇航员Bob有一天来到火星上,他有收集硬币的习惯。于是他将火星上所有面值的硬币都收集起来了,一共有n种,每种只有一个:面值分别为a1,a2… an。 Bob在机场看到了一个特别喜欢的礼物,想买来送给朋友Alice,这个礼物的价格是X元。Bob很想知道为了买这个礼物他的哪些硬币是必须被使用的,即Bob必须放弃收集好的哪些硬币种类。飞机场不提供找零,只接受恰好X元。

    输入第一行包含两个正整数n和x。(1 <= n <= 200, 1 <= x <= 10000)
    第二行从小到大为n个正整数a1, a2, a3 … an (1 <= ai <= x)输出第一行是一个整数,即有多少种硬币是必须被使用的。
    第二行是这些必须使用的硬币的面值(从小到大排列)。样例输入

    5 18
    1 2 3 5 10

    样例输出

    2
    5 10

    提示

    输入数据将保证给定面值的硬币中至少有一种组合能恰好能够支付X元。
    如果不存在必须被使用的硬币,则第一行输出0,第二行输出空行。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <string.h>
     4 #include <algorithm>
     5 #include <stdlib.h>
     6 #include <math.h>
     7 #include <queue>
     8 
     9 using namespace std;
    10 
    11 const int maxn1 = 205,maxn2=10005;
    12 int dp[maxn2],coin[maxn1],f[maxn2];
    13 int n,x,sum;
    14 queue<int> res;
    15 
    16 void print() {
    17     int p = res.front();
    18     printf("%d", coin[p]);
    19     res.pop();
    20     while (res.empty() != 1) {
    21         int p = res.front();
    22         printf(" %d", coin[p]);
    23         res.pop();
    24     } 
    25     printf("
    ");
    26 }
    27 
    28 void dpsolve() {
    29     for(int i=1;i<=n;i++)
    30         for (int j = x; j >= coin[i]; j--) {
    31             dp[j] += dp[j - coin[i]];
    32         }
    33     for (int i = 1; i <= n; i++)
    34     {
    35         memset(f, 0, sizeof(f));
    36         f[0] = 1;
    37         for (int j = 1; j <= x; j++)
    38         {
    39             if (coin[i] > j)
    40                 f[j] = dp[j];
    41             else 
    42                 f[j] = dp[j] - f[j - coin[i]];
    43         } 
    44         if (f[x] == 0) {
    45             sum++;
    46             res.push(i);
    47         }
    48     }
    49     printf("%d
    ", sum);
    50     if (sum)
    51         print();
    52     else
    53         printf("
    ");
    54 }
    55 
    56 void init() {
    57     cin >> n >> x;
    58     int c = n,_c=1;
    59     while (c--) 
    60         cin >> coin[_c++];
    61     sort(coin + 1, coin + n + 1);
    62     dp[0] = 1;
    63 }
    64 
    65 
    66 int main()
    67 {
    68     init();
    69     dpsolve();
    70     return 0;
    71 }
    View Code

    我为啥数组又开小了……浑然不知地RE了三次

    解题思路

    01背包算到达某价钱  x  时的总方案数 dp[x] 

    然后用方程 f[y]=dp[y]-f[y-coin[x]] 算出不用某硬币  x  时凑成  y  时的种数(虽然x不同,但我在每个循环里都是用的 f[y] )

     f[y] 为0就表示不能不用它~

    D:最佳加法表达式

    描述

    给定n个1到9的数字,要求在数字之间摆放m个加号(加号两边必须有数字),使得所得到的加法表达式的值最小,并输出该值。例如,在1234中摆放1个加号,最好的摆法就是12+34,和为36

    输入有不超过15组数据
    每组数据两行。第一行是整数m,表示有m个加号要放( 0<=m<=50)
    第二行是若干个数字。数字总数n不超过50,且 m <= n-1输出对每组数据,输出最小加法表达式的值样例输入

    2
    123456
    1
    123456
    4
    12345
    

    样例输出

    102
    579
    15
    

    提示

    要用到高精度计算,即用数组来存放long long 都装不下的大整数,并用模拟列竖式的办法进行大整数的加法。

    来源

    Guo Wei

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <string.h>
      4 #include <algorithm>
      5 #include <stdlib.h>
      6 #include <math.h>
      7 #include <queue>
      8 
      9 using namespace std;
     10 
     11 const int maxn = 60;
     12 int m,countnum=0;//countnum为数字的位数
     13 char num[maxn];
     14 
     15 class bignum {
     16 public:
     17     int longnum[maxn];
     18     int revs[maxn];
     19     int len;
     20     bignum(){
     21         memset(longnum, 0, sizeof(longnum));
     22         memset(revs, 0, sizeof(longnum));
     23         len = 50;
     24     }
     25     bignum(char*a) {
     26         memset(longnum, 0, sizeof(longnum));
     27         memset(revs, 0, sizeof(longnum));
     28         for (int i = 0; a[i] != ''; i++)
     29             longnum[i] = a[i] - '0';
     30         len = strlen(a);
     31         for (int i = 0; i < len; i++)
     32             revs[i] = longnum[len-1 - i];
     33     }
     34     bignum(char*a, char*b) {
     35         memset(longnum, 0, sizeof(longnum));
     36         memset(revs, 0, sizeof(longnum));
     37         for (int i = 0; i <= b - a; i++)
     38             longnum[i] = *(a + i) - '0';
     39         len = b - a + 1;
     40         for (int i = 0; i < len; i++)
     41             revs[i] = longnum[len-1 - i];
     42     }
     43     bignum operator+(bignum x) {
     44         int res[maxn] = { 0 }; char _res[maxn]; int lenres;
     45         for (int i = 0; i < len || i < x.len; i++) {
     46             res[i] += revs[i] + x.revs[i];
     47             lenres = i;
     48             while (res[i] > 9) {
     49                 res[i] -= 10;
     50                 res[i + 1]++;
     51                 lenres = i + 1;
     52             }
     53         }
     54         for (int i = 0; i <= lenres; i++)
     55             _res[i] = res[lenres - i]+'0';
     56         return bignum(_res, _res + lenres);
     57     }
     58     bool operator<(bignum&x) {
     59         if (len < x.len)return true;
     60         if (len > x.len)return false;
     61         for (int i = 0; i < len; i++)
     62         {
     63             if (longnum[i] > x.longnum[i])
     64                 return false;
     65             else if(longnum[i] < x.longnum[i]) return true;
     66         }
     67         return true;
     68     }
     69 };
     70 
     71 bignum dp[maxn][maxn];//dp[x][y]为前y个数字里有x个加号
     72 bignum _num;
     73 
     74 void clear() {
     75     for (int i = 0; i <= m; i++)
     76         for (int j = 1; j <= countnum; j++)
     77             dp[i][j] = bignum();
     78 }
     79 
     80 void dpsolve() {
     81     for(int i=1;i<=m;i++)
     82         for (int j = i + 1; j <= countnum; j++) {
     83             for (int k = i; k < j; k++) {
     84                 bignum res = dp[i - 1][k] + bignum(num + k, num+j - 1);
     85                 if (res < dp[i][j])
     86                     dp[i][j] = res;
     87             }
     88         }
     89 }
     90 
     91 void init() {
     92     while (cin >> m) {
     93         cin >> num;
     94         countnum = strlen(num);
     95         clear();
     96         _num = bignum(num);
     97         for (int i = 1; i <= countnum; i++)
     98             dp[0][i] = bignum(num, num + i - 1);
     99         dpsolve();
    100         for (int i = 0; i < dp[m][countnum].len; i++)
    101             printf("%d", dp[m][countnum].longnum[i]);
    102         printf("
    ");
    103     }
    104 }
    105 
    106 
    107 int main()
    108 {
    109     init();
    110     dpsolve();
    111     return 0;
    112 }
    View Code

    我怕不是C++学傻了

    满脑子C++.jpg

    解题思路

    这个最简单了,用 dp[x][y] 表示前y个数字加号有x的时候表达式最小值

    我里面有很多浪费计算,不管了

    主要是结合了高精度,比较麻烦,很容易错

    WA点:在每个case之间没有清空dp数组

    注定失败的战争,也要拼尽全力去打赢它; 就算输,也要输得足够漂亮。
  • 相关阅读:
    第四章5
    第四章4
    第四章3
    第四章2
    第四章1
    第四章例4-8
    第四章例4-7
    第四章例4-6
    第四章例4-5
    第四章例4-4
  • 原文地址:https://www.cnblogs.com/yalphait/p/9080560.html
Copyright © 2011-2022 走看看