编程练习1:动态规划

总体感受:
太久不做OJ好僵硬, 需要好好练习啊。
网站:http://acm.hust.edu.cn/vjudge/contest/130692#overview

A题:Cutting Sticks

题目:

You have to cut a wood stick into pieces. The most affordable company, The Analog Cutting Machinery, Inc. (ACM), charges money according to the length of the stick being cut. Their procedure of work requires that they only make one cut at a time.
It is easy to notice that different selections in the order of cutting can led to different prices. For example, consider a stick of length 10 meters that has to be cut at 2, 4 and 7 meters from one end. There are several choices. One can be cutting first at 2, then at 4, then at 7. This leads to a price of 10 + 8 + 6 = 24 because the first stick was of 10 meters, the resulting of 8 and the last one of 6. Another choice could be cutting at 4, then at 2, then at 7. This would lead to a price of 10 + 4 + 6 = 20, which is a better price.
Your boss trusts your computer abilities to find out the minimum cost for cutting a given stick.
Input
The input will consist of several input cases. The first line of each test case will contain a positive number l that represents the length of the stick to be cut. You can assume l < 1000. The next line will contain the number n (n < 50) of cuts to be made.
The next line consists of n positive numbers ci (0 < ci < l) representing the places where the cuts have to be done, given in strictly increasing order.
An input case with l = 0 will represent the end of the input. Output
You have to print the cost of the optimal solution of the cutting problem, that is the minimum cost of cutting the given stick. Format the output as shown below.
Sample Input
100
3
25 50 75 10
4 4578 0
Sample Output
The minimum cutting is 200.
The minimum cutting is 22.

想法:

题意要理解清楚,刀数是不用考虑的,因为要切在哪里已经给出,递归表达式中不会出现还差几刀(这里想了好久,感觉还是做题太少)。
写出递归表达式:

f(i,j)=minf(i,k)+f(k,j)+len(j)len(i)(i<k<j)

常规的dp解法,三重循环,第一重对长度,第二重起点,第三重k值。

代码:

#include <iostream>
#include <vector>
#include <string.h>
using namespace std;
#define MAX 1001


int main(int argc, const char * argv[]) {
    int length;
    int n;
    int len,i, j, k;
    int a[MAX];
    int dp[MAX][MAX];
    while(cin>>length){
        if(length == 0)
            break;
        cin >> n;
        memset(a,0,MAX*sizeof(int));
        a[0] = 0;
        for (i = 1; i <= n; i++){
            cin >> a[i];
        }
        a[n+1] = length;
        memset(dp,0,MAX*MAX*sizeof(int));
        for(len = 2; len <= n+1; len++ ){
            for(i = 0; i <=n+1 - len ; i++){
                j = i + len;
                for(k =i+1; k<j;k++ ){
                    if (dp[i][j] == 0){
                        dp[i][j] = dp[i][k] + dp[k][j] + a[j] - a[i];
                     //  cout<<"dp"<<i<<j<<" = "<<dp[i][j]<<endl;
                    }
                    else{
                        dp[i][j] = min(dp[i][k] + dp[k][j] + a[j] - a[i], dp[i][j]);
                    }
                }
            }
        }
        cout << "The minimum cutting is " << dp[0][n+1]<<"."<<endl;
    }

    return 0;
}

网上一些比较简洁的代码:

http://blog.csdn.net/u013167299/article/details/46997891

B题:Max Sum

题目:

Given a sequence a[1],a[2],a[3]……a[n], your job is to calculate the max sum of a sub-sequence. For example, given (6,-1,5,4,-7), the max sum in this sequence is 6 + (-1) + 5 + 4 = 14.

Input
The first line of the input contains an integer T(1<=T<=20) which means the number of test cases. Then T lines follow, each line starts with a number N(1<=N<=100000), then N integers followed(all the integers are between -1000 and 1000).

Output
For each test case, you should output two lines. The first line is “Case #:”, # means the number of the test case. The second line contains three integers, the Max Sum in the sequence, the start position of the sub-sequence, the end position of the sub-sequence. If there are more than one result, output the first one. Output a blank line between two cases.

Sample Input
2
5 6 -1 5 4 -7
7 0 6 -1 1 -6 7 -5

Sample Output
Case 1:
14 1 4

Case 2:
7 1 6

想法:

这道题为什么是dp的题目呢?没有最优子结构性质,又写不出明显的递归表达式,但是网上好像都说是dp的题目,存在疑惑,以后补完。

代码:

#include <iostream>
#include <string.h>
using namespace std;
#define MAX 100005
//一开始int main这里报错,原因是开了int a[MAX][MAX],这个数组太大,直接爆栈了。
int main(int argc, const char * argv[]) {
    int times;
    int a[MAX];
    cin>>times;
    int i, j;
    int n;
    int maxsum, maxl, maxr, tempsum, templ, tempr;
    for (i = 1; i <= times; i++){
        cin >> n;
        for(j = 0; j < n; j++){
            cin >> a[j];
        }
        maxsum = tempsum = a[0];
        maxl = maxr = templ = tempr = 0;
        for (j = 1; j < n; j++){
            if(tempsum + a[j] < a[j]){
                templ = j;
                tempsum = a[j];
            }else{
                tempr = j;
                tempsum = tempsum + a[j];
            }
            //注意:下面的语句不在上面的else里面,要考虑全面。
            if (tempsum > maxsum){
                maxsum = tempsum ;
                maxl = templ;
                //maxr = tempr这里有坑,tempr又可能是之前的
                maxr = j;
            }
        }
        maxl += 1;
        maxr += 1;
        cout << "Case " << i << ":" << endl;
        cout << maxsum << " " << maxl << " " << maxr << endl;
        //注意格式
        if (i != times)
            cout << endl;
    }
    return 0;
}

可以参考的一些解法:

http://blog.csdn.net/akof1314/article/details/4757021

C题:Brackets sequence

题目:

Let us define a regular brackets sequence in the following way:

  1. Empty sequence is a regular sequence.

  2. If S is a regular sequence, then (S) and [S] are both regular sequences.

  3. If A and B are regular sequences, then AB is a regular sequence.

For example, all of the following sequences of characters are regular brackets sequences:

(), [], (()), ([]), ()[], ()[()]

And all of the following character sequences are not:

(, [, ), )(, ([)], ([(]

Some sequence of characters ‘(‘, ‘)’, ‘[‘, and ‘]’ is given. You are to find the shortest possible regular brackets sequence, that contains the given character sequence as a subsequence. Here, a string a1 a2 … an is called a subsequence of the string b1 b2 … bm, if there exist such indices 1 = i1 < i2 < … < in = m, that aj = bij for all 1 = j = n.

Input

The input file contains at most 100 brackets (characters ‘(‘, ‘)’, ‘[’ and ‘]’) that are situated on a single line without any other characters among them.

Output

Write to the output file a single line that contains some regular brackets sequence that has the minimal possible length and contains the given sequence as a subsequence.

This problem contains multiple test cases!

The first line of a multiple input is an integer N, then a blank line followed by N input blocks. Each input block is in the format indicated in the problem description. There is a blank line between input blocks.

The output format consists of N output blocks. There is a blank line between output blocks.

Sample Input

1

([(]

Sample Output

()[()]

想法:

想法见该博客:
http://blog.sina.com.cn/s/blog_7d3ee9f5010126fh.html
下面是我的错误代码,到最后都没有过不想debug了,先放在这里等日后有空了再说吧。

#include <iostream>
#include <string.h>
using namespace std;

char str[105];
//用来记录有几个配对的括号
int dp[150][150];
//用来记录i,j中最大配对的k,-1表示未配对,-2表示i,j是最大配对,其他正数表示k
int log[150][150];
//用来记录某个括号是否配对了,用dfs标记
int a[150];

void dfs(int i, int j){
    if(i > j)
        return;
    if (log[i][j] == -2) {
        a[i] = a[j] = 1;
        dfs(i+1, j-1);
    }else if(log[i][j] >= 0){
         dfs(i, log[i][j]);
         dfs(log[i][j]+1, j);
    }
    return;
}
int main(int argc, const char * argv[]) {
   // freopen("input.txt", "r", stdin);
  //  freopen("output.txt", "w", stdout);
    int times;
    int length, len, i, j, k, startend;
    cin >> times;
    getchar();
    while(times--){
        getchar();
        gets(str);
        memset(dp, 0, sizeof(dp));
        memset(log, -1, sizeof(log));
        length = strlen(str);
        if(!length)
        {
            printf("\n");
            if(times)
                printf("\n");
            continue;
        }

        for (len = 1; len <= length; len++) {
            startend = length - len;
            for (i = 0; i <= startend ; i++) {
                j = i + len - 1;
                if (i == j) {
                    dp[i][j] = 0;
                }
                else if((str[i] =='('&&str[j] == ')') || (str[i] == '['&& str[j] == ']')){
                    if (i+1 > j-1) {
                        dp[i][j] = 1;
                        log[i][j] = -2;

                    }else if (dp[i+1][j-1] + 1 > dp[i][j]) {
                        dp[i][j] = dp[i+1][j-1] + 1;
                        log[i][j] = -2;
                    }
                    for (k = i ; k < j; k++) {
                        if (dp[i][k] + dp[k+1][j] > dp[i][j]) {
                            dp[i][j] = dp[i][k] + dp[k+1][j];
                            log[i][j] = k;
                        }

                    }
                }
                else{
                    for (k = i;  k < j; k++) {
                        if (dp[i][k] + dp[k+1][j] > dp[i][j]) {
                            dp[i][j] = dp[i][k] + dp[k+1][j];
                            log[i][j] = k;
                        }

                    }
                }
            }
        }
        memset(a, 0, sizeof(a));
        dfs(0, length - 1);
        for (i = 0; i < length; i++) {
            if (a[i] == 1) {
                cout<<str[i];
            }else{
                if ((str[i] == '(') || (str[i] == ')')) {
                    cout<<"()";
                }else if ((str[i] == '[') || (str[j] == ']')){
                    cout << "[]";
                }
            }
        }
        cout << endl;
        if (times) {
            cout << endl;
        }
    }
    return 0;
}

D题:Cake Slicing(记忆化搜索)

#include<iostream>
#include<string.h>
using namespace std;
int INF = 1000;
int dp[25][25][25][25];
bool cherry[25][25];

int sum(int u, int d, int l, int r){
    int ret1, i, j;
    ret1 = 0;//初始化一定不要忘记
    for (i = u; i <= d; i++){
        for (j = l; j <= r; j++) {
            if(cherry[i][j]){
                ret1++;
            }
            if(ret1 == 2){
                //大于2的情况统一为二
                return 2;
            }
        }
    }
    if(ret1 == 1)
        return 1;
    else{
        //no cherry
        return 0;
    }
}

int solve(int u, int d, int l, int r){
    int i;
    int &ret = dp[u][d][l][r];
    if(ret != -1)
        return ret;
    int total = sum(u, d, l, r);
    if (total == 1) {
        return ret = 0;
    }
    if (!total){
        return ret = INF;
    }
    ret = INF;
        //total = 2
    for (i = u; i < d; i++) {
        //从上往下遍历,从左往右切
        ret = min(ret, solve(u, i, l, r) + solve(i+1, d, l, r) + r - l + 1);
    }
    for (i = l; i < r; i++) {
        //从左往右遍历,从上往下切
        ret = min(ret, solve(u, d, l, i) + solve(u, d, i+1, r) + d - u + 1);
    }
    return ret;
}

int main(int argc, const char * argv[]) {
//    freopen("input.txt", "r",stdin);
//    freopen("output.txt", "w", stdout );
    int n, m, numOfCherry;
    int positionx, positiony;
    int times = 1;
    while(cin >> n >> m >> numOfCherry){
        memset(dp, -1, sizeof(dp));
        memset(cherry, 0, sizeof(cherry));
        for (int i = 0; i < numOfCherry; i++) {
            cin >> positionx >> positiony;
            cherry[positionx][positiony] = true;
        }
        cout << "Case " << times++ << ":" << " " <<solve(1, n, 1, m) <<endl;
    }
    return 0;
}

可以参考的解法:
http://blog.csdn.net/catglory/article/details/47434293

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值