poj-1836

22 篇文章 0 订阅
//380K 79MS    G++
#include <cstdio>
#include <cstring>

using namespace std;

double soldiers[1005];

struct soldierInfo{
    double prevHeight;
    int num;
};

typedef struct soldierInfo soldierInfo;

soldierInfo aux[1005];

int tmpSolider[1002];

int soldierNum;

int lengthMAX;

#define INF 999999

// void solve() {
//     int beginSoldierId = 1;
//     lengthMAX = -INF;
//     memset(aux, 0, sizeof(aux));
//     while(1) {
//         if (beginSoldierId > soldierNum){
//             break;
//         }
//         int thisTimeSoldierNum = 0;
//         if (aux[beginSoldierId].num == 0) {
//             printf("C %d", beginSoldierId);
//             int i = 0;
//             aux[beginSoldierId].num = 1;
//             aux[beginSoldierId].prev
//             tmpSolider[thisTimeSoldierNum++] = beginSoldierId;
//             for (i = beginSoldierId; i <= soldierNum; i++) {
//                 if (soldiers[i] < soldiers[beginSoldierId]) {
//                     if (aux[i].num > 0) {
//                         for (int i = 0; i < thisTimeSoldierNum; i++) {
//                             int soldierId = tmpSolider[i];
//                             aux[soldierId].num = thisTimeSoldierNum - i + aux[i].num;
//                         }
//                         break;
//                     } else {
//                         tmpSolider[thisTimeSoldierNum++] = i;
//                         // thisTimeSoldierNum++;
//                     }
//                 }
//             }
//             if (i == soldierNum + 1) {
//                 printf("B %d\n", beginSoldierId);
//                 for (i = 0; i < thisTimeSoldierNum; i++) {
//                     printf("V %d %d\n", tmpSolider[i], thisTimeSoldierNum - i);
//                     int soldierId = tmpSolider[i];
//                     aux[soldierId].num = thisTimeSoldierNum - i;
//                 }
//             }
//         }
//         printf("%d %d\n", aux[beginSoldierId].num, beginSoldierId);
//         lengthMAX = lengthMAX > aux[beginSoldierId].num ? lengthMAX : aux[beginSoldierId].num;
//         beginSoldierId++;
//     }
//     printf("%d\n", soldierNum - lengthMAX);
// }

int DP[1005];
int DP2[1005];

int solve2() {

    memset(DP, 0, sizeof(DP));
    memset(DP2, 0, sizeof(DP2));

    // jiang
    for (int i = soldierNum; i >= 1; i--) {
        if (i == soldierNum) {
            DP[i] = 1;
        } else {
            int MAXLEN = 1;
            for (int j = i+1; j <= soldierNum; j++) {
                // printf("%d %d %lf %lf\n", i, j, soldiers[i], soldiers[j]);
                if (soldiers[j] < soldiers[i]) {
                    int length = DP[j] + 1;
                    MAXLEN = MAXLEN > length ? MAXLEN: length;
                }
            }
            DP[i] = MAXLEN;
        }
        // printf(" < %d %d\n", DP[i], i);
    }

    //sheng
    for (int i = 1; i <= soldierNum; i++) {
        if (i == 1) {
            DP2[i] = 1;
        } else {
            int MAXLEN2 = 1;
            for (int j = 1; j <= i-1; j++) {
                // printf("%d %d %lf %lf\n", i, j, soldiers[i], soldiers[j]);
                if (soldiers[j] < soldiers[i]) {
                    int length = DP2[j] + 1;
                    MAXLEN2 = MAXLEN2 > length ? MAXLEN2: length;
                }
            }
            DP2[i] = MAXLEN2;
        }
        // printf(" > %d %d\n", DP2[i], i);
    }

    int MAXLEN3 = DP2[soldierNum] > DP[1] ? DP2[soldierNum] : DP[1];
    // printf("%d\n", MAXLEN3);

    if (soldierNum >= 3) {
        for (int split = 2; split <= soldierNum-1; split++) {
            // memset(DP, 0, sizeof(DP));
            // memset(DP2, 0, sizeof(DP2));
            // //jiang
            // int maxlength1 = 0;
            // int jiangBegin = split;
            // for (int i = soldierNum; i >= split + 1; i--) {
            //     if (soldiers[i] < soldiers[split]) {
            //         if (i == soldierNum) {
            //             DP[i] = 1;
            //         } else {
            //             int MAXLEN = 1;
            //             for (int j = i+1; j <= soldierNum; j++) {
            //                 // printf("%d %d %lf %lf\n", i, j, soldiers[i], soldiers[j]);
            //                 if ((soldiers[j] < soldiers[i]) &&
            //                     (soldiers[j] < soldiers[split]) &&
            //                     (soldiers[i] < soldiers[split])) {
            //                     int length = DP[j] + 1;
            //                     MAXLEN = MAXLEN > length ? MAXLEN: length;
            //                 }
            //             }
            //             DP[i] = MAXLEN;
            //         }
            //     }
            //     if (maxlength1 < DP[i]) {
            //         maxlength1 = DP[i];
            //         jiangBegin = i;
            //     }
            //     // maxlength1 = DP[i] > maxlength1 ? DP[i]: maxlength1;
            //     // printf(" > %d %d\n", DP[i], i);
            // }

            // //sheng
            // int maxlength2 = 0;
            // int shengEnd = split;
            // for (int i = 1; i <= split-1; i++) {
            //     if (soldiers[i] < soldiers[split]) {
            //         if (i == 1) {
            //             DP2[i] = 1;
            //         } else {
            //             int MAXLEN2 = 1;
            //             for (int j = 1; j <= i-1; j++) {
            //                 // printf("%d %d %lf %lf\n", i, j, soldiers[i], soldiers[j]);
            //                 if ((soldiers[j] < soldiers[i]) &&
            //                     (soldiers[j] < soldiers[split]) &&
            //                     (soldiers[i] < soldiers[split])) {
            //                     int length = DP2[j] + 1;
            //                     MAXLEN2 = MAXLEN2 > length ? MAXLEN2: length;
            //                 }
            //             }
            //             DP2[i] = MAXLEN2;
            //         }
            //     }
            //     if (maxlength2 < DP2[i]) {
            //         maxlength2 = DP2[i];
            //         shengEnd = i;
            //     }
            //     // maxlength2 = DP2[i] > maxlength2 ? DP2[i]: maxlength2;
            //     // printf(" < %d %d\n", DP2[i], i);
            // }

            int maxlength1 = 0;
            int maxlength2 = 0;
            int jiangBegin = split;
            int shengEnd = split;
            //sheng
            for (int i = 1; i <= split-1; i++) {
                if (soldiers[split] > soldiers[i]) {
                    if (maxlength1 < DP2[i]) {
                        shengEnd = i;
                        maxlength1 = DP2[i];
                    }
                }
            }

            //jiang
            for (int i =soldierNum; i >= split+1; i--) {
                if (soldiers[split] > soldiers[i]) {
                    if (maxlength2 < DP[i]) {
                        jiangBegin = i;
                        maxlength2 = DP[i];
                    }
                }
            }

            int heightEqualNum = 0;
            int heightEqualNum1 = 0;
            for (int i = shengEnd + 1; i <= jiangBegin -1; i++) {
                if (soldiers[i] == soldiers[split]) {
                    heightEqualNum++;
                    if (heightEqualNum >=2) {
                        heightEqualNum1 = 1;
                        break;
                    }
                }
            }
            // printf("%d %d\n", shengEnd, jiangBegin);
            // printf("%d %d %d %d\n", split, maxlength1, maxlength2, heightEqualNum);
            int tmpMAXLEN = maxlength1 + maxlength2 + 1 + heightEqualNum1;
            MAXLEN3 = tmpMAXLEN > MAXLEN3 ? tmpMAXLEN: MAXLEN3;
            // printf("%d %d\n", split, MAXLEN3);
        }
    }

    printf("%d\n", soldierNum - MAXLEN3);
}

int main() {
    while(scanf("%d", &soldierNum) !=EOF) {
        for (int i = 1; i <= soldierNum; i++) {
            scanf("%lf", &soldiers[i]);
        }
        // solve();
        solve2();
    }
}

发现自己现在对DP又有点手生了,连基本的最长递增序列的求法都给忘了。

这道题难不在DP本身,而在于一些细节处理,题目的要求比较苛刻:

调整队列以后,每个士兵都能至少看到最左边或者最右边的人,注意,是或者,并且又是左右两边,这样就不是一个单纯的求最长递增/递减序列了,

因为可以在中间找一个最高的士兵,然后向两边递减,这就成了一个最长递增序列和最短递增序列的组合了

比如 对于队列 S:

3 4 5 1 2 5 4 3
这组队列可以这样排:

3 4 5 4 3, 最高的士兵5在中间,然后向左与右递减,但是,注意了,这还不是最优的解!因为题目只要求了能看到最左/最右,那么可以这么排:

3 4 5 5 4 3,

这样排,两个身高为5的士兵在中间,分别可以看到最左/右,是一个最优解(最长的队列)。

这样,考虑到这些因素,本题就变得有些麻烦了,

先要对整个数组求一次 最长递增/递减序列, 

相应的DP数组:

DP1[]对应递增,DP1[i] 表示 以S[i] 结尾的(从S[1]开始的)递增序列的最长长度。

DP2[]对应递减,DP2[i]表示 以S[i]开头的(以S[N]结束的)递减序列的最长长度,

可以得到这两种方式下的最长序列 LX LY,

然后还有枚举每个士兵,考虑以此士兵最为最后队列的中间最高者进行求队列长度,

如果以士兵 i 作为中间最高者,那么就要求其左边的最长递增序列和右边的最长递减序列,要注意的是,这里的递增序列最大值不能搞过S[i], 同样递减序列最大值也不能超过S[i], 我在这里犯迷糊了,还又重新求了一次递增和递减,其实根本不用的,因此之前的DP1和DP2已经包含了这个信息:

对于S[i]左边, 只需求出最大的DP1[j], 且S[j] <S[i] 即可,同样,右边,只需求出最大的DP2[j], S[j] < S[i]即可,

还有一个细节: 因为要考虑 i左边/右边可以有一个和自己一样身高的士兵(只能一边有,不能两边都有),

这个一样身高的士兵,如果有的话,且符合题目需求的话,必然在最后的队列是和i紧挨的(不挨的话,就不可能递增/递减了), 因此,

设i 左边的最长递增序列的结束位置是 left, i右边的最长递减序列的开始位置是 right,

那么 如果有符合条件的同样身高士兵m, 那么分布只能是这样的:

....left.....m.....i.....right 或  .....left....i....m.....right, 

通过这个就可以检测是否有士兵m了,遍历从 left+1 到 right-1的序列,如果有 >1(包含 i 本身,因此要>1表示除了i还有别的一样身高的士兵)个 和i同样身高的士兵,那么就有m存在,但只能选择一个m(如果有两个m,就不满足题了), 

到了这一步,基本完成了,但还有个细节, 如果 左边/右边的最长递增/递减 序列有多个同等长度的最长序列,那么left 和 right应该 选择 left最小 ,right最大的序列,

这样能保证挑选m的序列最长,如果有m存在,就一定能找到. 还有就是考虑i在最左和最右的情况了, 这时候,左边/右边有一边不用考虑,

左边最长递增序列长度L1和和右边最长递减序列长度L2的初始值要是0(比如 5 6 9, 选6做i的话,左边,右边都没有比i小的递增/递减序列)

最后的长度是 L1 + L2 + 1 (如果有m存在) + 1(i 本身就是最终序列的一部分)


结合之前的LX LY ,以及遍历每个点的最后长度,找到的最长序列就是最终序列,

要出列的人数,就是原来队列长度减去最终序列长度即可.

这道题很考察细节,以后应该多练练这种题.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值