poj-1836

来源:互联网 发布:数据字典的功能 编辑:程序博客网 时间:2024/06/06 04:04
//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 ,以及遍历每个点的最后长度,找到的最长序列就是最终序列,

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

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

0 0
原创粉丝点击