《程序設計與算法(二)算法基礎》《第六週 分治》動態規劃 Triangle 最長上升子序列 公共子序列 最佳加法表達式(HARD) 1163 2757 1458 4152

1163:The Triangle

總時間限制: 
1000ms
 
內存限制: 
65536kB
描述
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

(Figure 1)

Figure 1 shows a number triangle. Write a program that calculates the highest sum of numbers passed on a route that starts at the top and ends somewhere on the base. Each step can go either diagonally down to the left or diagonally down to the right.
輸入
Your program is to read from standard input. The first line contains one integer N: the number of rows in the triangle. The following N lines describe the data of the triangle. The number of rows in the triangle is > 1 but <= 100. The numbers in the triangle, all integers, are between 0 and 99.
輸出
Your program is to write to standard output. The highest sum is written as an integer.
樣例輸入
5
7
3 8
8 1 0 
2 7 4 4
4 5 2 6 5
樣例輸出
30
/*
http://bailian.openjudge.cn/practice/1163/
1163:The Triangle
遞歸解法2:數字三角形的記憶遞歸型動歸程序
*/
#include<iostream>
#include<algorithm>
#define MAX 101
using namespace std;
int D[MAX][MAX];
int sum[MAX][MAX];
int n;
int MaxSum(int i, int j)
{
    if (sum[i][j] != -1)/*說明這個路徑的最大和已經算過了*/
    {
        return sum[i][j];
    }
    if (i == n)
    {
        sum[i][j] = D[i][j];
    }
    else
    {
        int x = MaxSum(i + 1, j);
        int y = MaxSum(i + 1, j + 1);
        sum[i][j] = max(x, y) + D[i][j];
    }
    return sum[i][j];
}
int main()
{
    int i, j;
    cin >> n;
    for (i = 0; i < n; i++)
    {
        for (j = 0; j <= i; j++)
        {
            cin >> D[i][j];
            sum[i][j] = -1;
        }
    }
    cout << MaxSum(0, 0) << endl;
    return 0;

}

 

/*
The Triangle
遞歸轉成遞推
*/
#include<iostream>
#include<algorithm>
using namespace std;

int n;
#define MAX 101
int D[MAX][MAX];
int maxsum[MAX][MAX];

int main()
{
    int i, j;
    cin >> n;
    for (i = 0; i < n; i++)
    {
        for (j = 0; j <= i; j++)
        {
            cin >> D[i][j];
        }
    }
    for (i = n - 1; i >= 0; i--)
    {
        for (j = 0; j <= n - 1; j++)
        {
            if (i == n - 1)
            {
                maxsum[i][j] = D[i][j];
            }
            else
            {
                maxsum[i][j] = max(maxsum[i + 1][j], maxsum[i + 1][j + 1]) + D[i][j];
            }

        }

    }
    cout << maxsum[0][0] << endl;
    return 0;
}

 

/*
The Triangle
遞歸轉成遞推
空間優化
用一維數組替代二維數組
進一步考慮,連maxSum 數組均可以不要,直接用 D 的第 n 行替代 maxSum 便可。
節省空間,時間複雜度不變
*/
#include<iostream>
#include<algorithm>
using namespace std;

int n;
#define MAX 101
int D[MAX][MAX];
int *maxsum;
int main()
{
    int i, j;
    cin >> n;
    for (i = 0; i < n; i++)
    {
        for (j = 0; j <= i; j++)
        {
            cin >> D[i][j];
        }
    }
    maxsum = D[n-1];/* maxSum 指向第 n 行 */

    for (i = n - 2; i >= 0; i--)
    {
        for (j = 0; j <= n - 2; j++)
        {
            maxsum[j] = max(maxsum[j] ,maxsum[j + 1]) + D[i][j];

        }

    }
    cout << maxsum[0] << endl;
    return 0;
}

 

2757:最長上升子序列

總時間限制: 
2000ms
 
內存限制: 
65536kB
描述
一個數的序列 bi,當 b1 <  b2 < ... <  bS的時候,咱們稱這個序列是上升的。對於給定的一個序列( a1a2, ...,  aN),咱們能夠獲得一些上升的子序列( ai1ai2, ...,  aiK),這裏1 <=  i1 <  i2 < ... <  iK <= N。好比,對於序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。這些子序列中最長的長度是4,好比子序列(1, 3, 5, 8).

你的任務,就是對於給定的序列,求出最長上升子序列的長度。
輸入
輸入的第一行是序列的長度N (1 <= N <= 1000)。第二行給出序列中的N個整數,這些整數的取值範圍都在0到10000。
輸出
最長上升子序列的長度。
樣例輸入
7
1 7 3 5 9 4 8
樣例輸出
4
/*
Dynamic Planning
http://bailian.openjudge.cn/practice/2757
2757:最長上升子序列
思路:找子問題
1. 「求序列的前n 個元素的最長上升子序列的長度 是個子問題,但這樣分解子問題,不具備「無後效性」
2. 「求以ak( k=1, 2, 3…N )爲終點的最長上升子序列的長度」
*/

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

const int MAXN = 1010;
int a[MAXN];
int maxLen[MAXN];

int main()
{
    int N;
    cin >> N;
    for (int i = 1; i <= N; i++)
    {
        cin >> a[i];
        maxLen[i] = 1;
        for (int i = 2; i <= N; ++i)
        {
            for (int j = 1; j < i; ++j)
            {
                if (a[i] > a[j])
                {/*要遍歷子問題的最長子序列,j=1,2,3..., 有可能j=2  > j=3, 因此要記錄j=2時的最大值
                 ,防止j=3時,刷掉上一個實際的最優解 */
                    maxLen[i] = max(maxLen[i], maxLen[j] + 1);
                }
            }
        }
    }
    /* STL 函數*/
    cout << *max_element(maxLen + 1, maxLen + N + 1);
    return 0;
}

1458:Common Subsequence

總時間限制: 
1000ms
 
內存限制: 
65536kB
描述
A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = < x1, x2, ..., xm > another sequence Z = < z1, z2, ..., zk > is a subsequence of X if there exists a strictly increasing sequence < i1, i2, ..., ik > of indices of X such that for all j = 1,2,...,k, x ij = zj. For example, Z = < a, b, f, c > is a subsequence of X = < a, b, c, f, b, c > with index sequence < 1, 2, 4, 6 >. Given two sequences X and Y the problem is to find the length of the maximum-length common subsequence of X and Y.
輸入
The program input is from the std input. Each data set in the input contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct.
輸出
For each set of data the program prints on the standard output the length of the maximum-length common subsequence from the beginning of a separate line.
樣例輸入
abcfbc         abfcab
programming    contest 
abcd           mnp
樣例輸出
4
2
0

/*
http://bailian.openjudge.cn/practice/1458
1458:Common Subsequence
公共子序列
*/

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
char sz1[1000];
char sz2[1000];
int maxLen[1000][1000];
int main()
{
    while (cin >> sz1 >> sz2)
    {
        int length1 = strlen(sz1);
        int length2 = strlen(sz2);
        int nTmp;
        int i, j;
        /* 邊界條件,若是一個字符串沒有字符,默認最長公共子序列爲0 */
        for (i = 0; i <= length1; i++)
            maxLen[i][0] = 0;
        for (j = 0; j <= length2; j++)
            maxLen[0][j] = 0;
        for (i = 1; i <= length1; i++)
        {
            for (j = 1; j <= length2; j++)
            {
                if (sz1[i - 1] == sz2[j - 1])
                {
                    maxLen[i][j] = maxLen[i - 1][j - 1] + 1;
                }
                else
                {
                    maxLen[i][j] = max(maxLen[i][j - 1], maxLen[i - 1][j]);
                }
            }
        }
        cout << maxLen[length1][length2] << endl;
    }
    return 0;
}

 

 

4152:最佳加法表達式

總時間限制: 
1000ms
 
內存限制: 
65536kB
描述

給定n個1到9的數字,要求在數字之間擺放m個加號(加號兩邊必須有數字),使得所獲得的加法表達式的值最小,並輸出該值。例如,在1234中擺放1個加號,最好的擺法就是12+34,和爲36ios

輸入
有不超過15組數據
每組數據兩行。第一行是整數m,表示有m個加號要放( 0<=m<=50)
第二行是若干個數字。數字總數n不超過50,且 m <= n-1
輸出
對每組數據,輸出最小加法表達式的值
樣例輸入
2
123456
1
123456
4
12345
樣例輸出
102
579
15
提示
要用到高精度計算,即用數組來存放long long 都裝不下的大整數,並用模擬列豎式的辦法進行大整數的加法。
/*
http://bailian.openjudge.cn/practice/4152/
4152:最佳加法表達式
*/
//By Guo Wei
#include <iostream>
#include <string>
#include <cstring>
#include<algorithm>
using namespace std;
struct BigInt
{

    int num[110];
    int len;
    BigInt operator+(const BigInt & n) { //重載+,使得 a + b在 a,b都是 BigInt變量的時候能成立
        int ml = max(len, n.len);
        int carry = 0; //進位 
        BigInt result;
        for (int i = 0; i < ml; ++i) {
            result.num[i] = num[i] + n.num[i] + carry;
            if (result.num[i] >= 10) {
                carry = 1;
                result.num[i] -= 10;
            }
            else
                carry = 0;
        }
        if (carry == 1) {
            result.len = ml + 1;
            result.num[ml] = 1;
        }
        else
            result.len = ml;
        return result;
    }
    bool operator<(const BigInt & n) {
        if (len > n.len)
            return false;
        else if (len < n.len)
            return true;
        else {
            for (int i = len - 1; i >= 0; --i) {
                if (num[i] < n.num[i])
                    return true;
                else if (num[i] > n.num[i])
                    return false;
            }
            return false;
        }
    }
    BigInt() {
        len = 1;
        memset(num, 0, sizeof(num));
    }
    BigInt(const char * n, int L) { //由長度爲L的char數組構造大整數。n裏面的元素取值範圍從 1-9。 
        memset(num, 0, sizeof(num));
        len = L;
        for (int i = 0; n[i]; ++i)
            num[len - i - 1] = n[i] - '0';
    }
};
ostream & operator <<(ostream & o, const BigInt & n)
{

    for (int i = n.len - 1; i >= 0; --i)
        o << n.num[i];
    return o;
}
const int MAXN = 60;
char a[MAXN];
BigInt Num[MAXN][MAXN];//Num[i][j]表示從第i個數字到第j個數字所構成的整數 
BigInt V[MAXN][MAXN]; //V[i][j]表示i個加號放到前j個數字中間,所能獲得的最佳表達式的值。 
int main()
{
    int m, n;
    BigInt inf; //無窮大 
    inf.num[MAXN - 2] = 1;
    inf.len = MAXN - 1;

    while (cin >> m) {
        cin >> a + 1;
        n = strlen(a + 1);
        for (int i = 1; i <= n; ++i)
            for (int j = i; j <= n; ++j) {
                Num[i][j] = BigInt(a + i, j - i + 1);
            }
        for (int j = 1; j <= n; ++j) {
            V[0][j] = BigInt(a + 1, j);
        }

        for (int i = 1; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                if (j - 1 < i)
                    V[i][j] = inf;
                else {
                    BigInt tmpMin = inf;
                    for (int k = i; k < j; ++k) {
                        BigInt tmp = V[i - 1][k] + Num[k + 1][j];
                        if (tmp < tmpMin)
                            tmpMin = tmp;
                    }
                    V[i][j] = tmpMin;
                }
            }
        }
        cout << V[m][n] << endl;
    }
    return 0;
}
相關文章
相關標籤/搜索