ZOJ Problem Set - 1025

ZOJ Problem Set - 1025

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1025

 

为了叙述方便,称一个可行的最优处理序列为合理序列。

在不reset前提下处理的序列称为序列的一个处理段。

显然根据题意可知,每个处理段中的数据都是有序的(按照长度以及重量非递减)。

我的做法是首先按照长度从小到大排好序。

 

之后就是贪婪算法:

以第一个结点为一个处理段B的头,按序遍历有序列L,若当前结点能够在不reset的情况下被处理,

则将该结点加入B的尾部,直至遍历完L产生一个完整的处理段B。

如此重复得到的处理段B[i]前后相接便得到一个合理序列,而i的范围就是reset次数。

用归纳法容易证明。

 

伪代码:

从序列头开始遍历排好序的列L,当遍历到某一个结点P(木棍)时,

1)若P为列头,则continue,否则转2)

2)若P为列尾,则转4),否则转3)

3)若P的重量不比前一个结点轻,则continue;否则将该结点移入tmp,取下一个结点,转2)

4)如果tmp为空,转7);否则取tmp第一个结点,转5)

5)若该结点的重量不比L最后一个轻,则将该结点移入L尾部,转4);否则转6)

6)若tmp没有下一个结点了,转4);否则取下一个结点,转5)

7)结束

 

或者碰到一个结点P就拿它去和现有的每个处理段的尾结点比重,若都比它们轻,则新建一个处理段,否则加入已有处理段。

两个方法前者占用空间少点,效率两者一样。

下面是我的代码。

 

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct Stick {
    int lengh;
    int weight;
};

bool NMT(const Stick& A, const Stick& B) {
    if(A.lengh < B.lengh) {
        return true;
    } else if(A.lengh == B.lengh) {
        return A.weight <= B.weight;
    } else {
        return false;
    }
}

int main()
{
    int iCase, iPair, spendTime;
    Stick tmp;
    vector<Stick> vSeq;
    vector<Stick>::iterator It;
    vector<Stick> vTmp;
    vector<Stick>::iterator itTmp;
    cin >> iCase;
    while(iCase--) {
        vSeq.clear();
        vTmp.clear();
        spendTime = 1;
        cin >> iPair;
        while(iPair--) {
            cin >> tmp.lengh >> tmp.weight;
            vSeq.push_back(tmp);
        }
        sort(vSeq.begin(), vSeq.end(), NMT);
        It = vSeq.begin();
        tmp = *It;
        while(It < vSeq.end()) {
            if(tmp.weight <= (*It).weight) {
                tmp = *It;
                It++;
            } else {
                vTmp.push_back((*It));
                It = vSeq.erase(It);
            }
        }
        while(vTmp.size()) {
            itTmp = vTmp.begin();
            tmp = (*itTmp);
            vSeq.push_back(tmp);
            itTmp = vTmp.erase(itTmp);
            while(itTmp != vTmp.end()) {
                if((*itTmp).weight >= tmp.weight) {
                    tmp = (*itTmp);
                    vSeq.push_back(tmp);
                    itTmp = vTmp.erase(itTmp);
                } else { itTmp++; }
            }
            spendTime++;
        }
        cout << spendTime << endl;
        for(int i=0;i<vSeq.size();i++) cout << "(" << vSeq[i].lengh << "," << vSeq[i].weight << "),";
        cout << endl;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值