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 ,以及遍历每个点的最后长度,找到的最长序列就是最终序列,
要出列的人数,就是原来队列长度减去最终序列长度即可.
这道题很考察细节,以后应该多练练这种题.
- POJ 1836
- POJ 1836
- poj 1836
- poj.1836
- poj-1836
- poj 1836
- poj 1836
- poj 1836
- poj 1836
- POJ 1836 Alignment
- POJ 1836 Alignment
- poj 1836 Alignment
- Poj 1836 Alignment
- poj 1836 Alignment
- POJ 1836-Alignment
- POJ 1836(双向LIS)
- poj 1836 Alignment
- POJ 1836 Alignment
- 【Visual C++】游戏开发笔记之十一 基础动画显示(四) 排序贴图
- Android最佳实践性能(一)管理您的应用程序的内存
- Kvm 深入学习
- CentOS 下GIT软软件的安装
- Tomcat的获取和安装
- poj-1836
- 【Visual C++】游戏开发笔记十二 游戏输入消息处理(一) 键盘消息处理
- 是什么系列之Avro
- 【Java】如何使用java synchronized进行线程同步
- uva920 扫描线水题
- hdu2053 a/b + c/d
- DelayQueue Demo
- 【Visual C++】游戏开发笔记十三 游戏输入消息处理(二) 鼠标消息处理
- Session机制。