Poj_1083 Moving Tables(贪心,测试数据)

题意:

房间之间通过单通道抬桌子,一共有400个房间,分别按照图上顺序编号。每次交换需要10分钟,当两个交换路径不重叠时可以在同一个时间间隔内完成。给出所有的搬动需求,问最少需要的时间。

思路:

最开始的思路就是模拟,首先把两边归为一边,按起点将所有交换排序后,每次都贪心的拿一遍,这样最后可以得到拿的次数。因为数据量不大,即便是O(n^2)的时间复杂度也不会超时,所以很快写出来了。但是却WA的很惨。。。虽然对贪心的思路不太确定,但是没找到反例。

后来参考了网上的做法,基本上都是遍历每一个交换区间,用一个数组记录过道i被遍历的次数,这样遍历次数最多的那个区间的次数乘以10,就是最少需要的时间。这个思路的证明可以参考这个回答:http://poj.org/showmessage?message_id=347563

这个思路确实十分巧妙,但是我还是一直在纠结我的算法为什么会错。尝试着证明了一下,发现对于经过次数最多的那个过道,我的每一次遍历也是一定经过它的,并且遍历的次数也不可能小于经过这个过道的次数(每次最多拿一个),所以也就是说遍历的次数一定等于经过次数最多的过道的次数,也就是说两个算法是等价的。后面经过调试发现思路确实是对的,WA在了中间对于每次遍历点的标记。

这道题收获还是很多的,坚持了自己的算法没有盲从,并且最后通过调试得到了证明。两个算法在时间复杂度上想通,我的空间复杂度可能更到一些,但是思路更加直接,如果是比赛的时候的话还是直接点好吧。

PS:中间cb罢工无法调试,搞了半天解决不了,结果搁置了两天自己好了。。。终于把这道题给debug了出来。

代码实现:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>

using namespace std;

struct Node{
    int sta;
    int en;
};

const int MAX = 210;

bool cmp(const Node& n1, const Node& n2){
    if( n1.sta != n2.sta ){
        return n1.sta<n2.sta;
    }
    return n1.en<n2.en;
}

int T;
int N;
int res;
Node lis[MAX];
bool flag[MAX];
int path[MAX];
int main(){
    scanf("%d",&T);
    while( T-- ){
        scanf("%d",&N);
        int a,b;
        res = 0;
        memset(flag,false,sizeof(flag));
        for( int i = 0; i < N; i++ ){
            scanf("%d%d",&a,&b);
            if( a%2 == 0 ){
                a /= 2;
            }
            else{
                a = (a-1)/2+1;
            }
            if( b%2 == 0 ){
                b /= 2;
            }
            else{
                b = (b-1)/2+1;
            }
            if( a > b ){
                swap(a,b);
            }
            lis[i].sta = a;
            lis[i].en = b;
        }
        int pos = 0;
        int dis = 0;
        sort(lis,lis+N,cmp);
        for( int i = 0; i < N; i++ ){
            if( flag[i] == true ){
                continue;
            }
            pos = i+1;
            flag[i] = true;
            dis = lis[i].en;
            res++;
            while( pos < N ){

                if( flag[pos] == true ){
                    pos++;
                    continue;
                }

                if( lis[pos].sta > dis ){
                    flag[pos] = true;
                    dis = lis[pos].en;
                }
                pos++;
            }
        }
        printf("%d\n",res*10);
    }
    return 0;
}

测试样例:

http://poj.org/showmessage?message_id=119066

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值