poj 1239 DP

动态规划解决数字串分隔问题

解析转自:点击打开链接

题目大意就是给定一些数字串,要你分别对每个数字串用逗号隔开,这样每个数字串中的数字保证是严格单调递增,且保证分隔后,最后的那个数字最小,当多种情况时要,那么取分隔后的第一个数字最大的,要是第一个数字也相同,那么看分隔后的第二个数字,如此下去,数字前面可以出现0,即000001表示1。

解题思考,两次动态规划。

第一次动态规划,保证最后的那个数字最小

dpforward[i]表示dpforward[i]~~~i这个段的数字串是上升子序列的一个数字;

dpforward[i] = max(dpforward[i], j+1),  其中dpforward[j]~j的数字串 小于 j+1 ~ i的数字串

对于全0的数字串要特殊处理,s1为全0,s2为全0,s1在s2的排列之前,那么s1 < s2,这样为了保重0能包括在子序列中

这样就能确定分隔后最后那个数字的宽度最小。

例如00010003对应的dpforward分别为0 1 2 3 3 3 3 4

dpforward[i]~~~i这个段的数字串是上升子序列的一个数字这段理解为,从后往前看,dp[7] = 4, 那么4 ~ dp[7]的数字为一个子串,

划分为0001,0003

确定了最后一个数字的最小宽度后,为了保证前几个数的第一,第二的序列最短,再进行一次反向的dp,从最后一个数字串前面一格往前进行dp

dpbackward[i] = max(dpbackward[i], j);  其中i~~j的数字串小于 j + 1~~~~dpbackward[j+1]的数字串

dpbackward[i]表示i~~~dpbackward[i]这个段的数字串是上升子序列的一个数字

最后根据dpbackward输出



AC代码如下:

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

char s[100];
int dpf[100], dpb[100];
int length;

bool judge( int a, int b, int c, int d ){
    int f1 = a, f2 = c;
    while( s[f1] == '0' && f1 <= b )   f1++;
    while( s[f2] == '0' && f2 <= d )   f2++;
    if( f1 > b ){
        return true;
    }
    if( f2 <= b && f1 >= d ){
        return false;
    }
    if( b - f1 + 1 < d - f2 + 1 ){
        return true;
    }else if( b - f1 + 1 > d - f2 + 1 ){
        return false;
    }
    while( f1 <= b && f2 <= d ){
        if( s[f1] > s[f2] ){
            return false;
        }else if( s[f1] < s[f2] ){
            return true;
        }
        f1++;
        f2++;
    }
    return false;
}

int main(){
    while( scanf( "%s", s + 1 ) && strcmp( s + 1, "0" ) != 0 ){
        s[0] = '0';
        dpf[0] = 0;
        length = strlen( s + 1 );
        memset( dpb, 0, sizeof( dpb ) );
        for( int i = 1; i <= length; i++ ){
            for( int j = i; j >= 1; j-- ){
                if( judge( dpf[j-1], j - 1, j, i ) ){
                    dpf[i] = j;
                    break;
                }
            }
        }
        int temp = dpf[length] - 1;
        dpb[dpf[length]] = length;
        while( s[temp] == '0' && temp >= 1 )   dpb[temp--] = length;
        for( int i = dpf[length] - 1; i >= 1; i-- ){
            for( int j = i; j < dpf[length]; j++ ){
                if( judge( i, j, j + 1, dpb[j+1] ) ){
                    dpb[i] = max( dpb[i], j );//注意这里
                }
            }
        }
        int i = 1;
        while( i <= length ){
            int temp = dpb[i];
            while( i <= temp ){
                cout << s[i++];
            }
            if( i <= length ){
                cout << ",";
            }
        }
        cout << endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值