USACO Section 3.2 PROB Spinning Wheels

题目:(摘自USACO官网)

Each of five opaque spinning wheels has one or more wedges cutout of its edges. These wedges must be aligned quickly and correctly.Each wheel also has an alignment mark (at 0 degrees) so that thewheels can all be started in a known position. Wheels rotate inthe `plus degrees' direction, so that shortly after they start,they pass through 1 degree, 2 degrees, etc. (though probably notat the same time).

This is an integer problem. Wheels are never actually at 1.5degrees or 23.51234123 degrees. For example, the wheels areconsidered to move instantaneously from 20 to 25 degrees during asingle second or even from 30 to 40 degrees if the wheel is spinningquickly.

All angles in this problem are presumed to be integers in therange 0 <= angle <= 359. The angle of 0 degrees follows theangle of 359 degrees. Each wheel rotates at a certain integernumber of degrees per second, 1 <= speed <= 180.

Wedges for each wheel are specified by an integer start angleand integer angle size (or `extent'), both specified in degrees.Wedges in the test data will be separated by at least one degree.The 'extent' also includes the original "degree" of the wedge, so'0 180' means degrees 0..180 inclusive -- one more than most wouldimagine.

At the start, which is time 0, all the wheels' alignment marksline up. Your program must determine the earliest time (integerseconds) at or after the start that some wedge on each wheel willalign with the wedges on the other wheel so that a light beam canpass through openings on all five wedges. The wedges can align atany part of the rotation.

PROGRAM NAME: spin

INPUT FORMAT

Each of five input lines describes a wheel.

The first integer on an input line is the wheel's rotation speed.The next integer is the number of wedges, 1 <= W <= 5. The nextW pairs of integers tell each wedge's start angle and extent.

SAMPLE INPUT (file spin.in)

30 1 0 120
50 1 150 90
60 1 60 90
70 1 180 180
90 1 180 60

OUTPUT FORMAT

A single line with a single integer that is the first time thewedges align so a light beam can pass through them. Print `none' (lowercase, no quotes) if the wedges will never align properly.

SAMPLE OUTPUT (file spin.out)

9

分析:

采用遍历,即每过一秒后,判断是否能有光线穿过。这里有两个关键问题:

1. 如何判断是否能有光线穿过;2. 什么时候应该终止,即永远都不能有光线穿过。


1. 判断光线穿过:

我首先想到的是采用深搜,即遍历各个轮子上Wedges的所有组合(最多5^5种)。但是实现起来非常困难,尤其是判断两个Wedge间重合区域时,情况特别多。

官方的思路:用一个数组unsigned int mark[360]来记录,每个wheel在每个角度能否通过。不同的wheel同个位运算来同时存入一个unsigned int中,即第i个wheel对应于 ox1 << i 这个 bit。这样每1秒后,就遍历所有的wheel上的Wedge,在mark中记录其能通过的角度;然后扫描mark,查看是否存在所有wheel能同时通过的角度。


2. 何时终止:

终止意味着5个Wheel又同时回到了当初的起始点,360秒即可。


注意:只需记录每个Wheel的角度,每次旋转时旋转该Wheel的角度,Wedge相对Wheel是不动的,所有不用去旋转Wedge。


小结:

解决问题是最怕的就是思维定势,钻到了死胡同里去了。解决问题时,一定要多问问自己,还有其它的方法吗?换个角度看看问题。


代码:

/*
ID: randyji1
PROG: spin
LANG: C++
*/



#include <fstream>
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cassert>
#include <cstring>
using namespace std;

ifstream fin("spin.in");
ofstream fout("spin.out");

const int NUM = 5;

struct Wheel {
    int speed;
    int n;
    int start[NUM];
    int extent[NUM];
    int position;
};

Wheel wheels[NUM];

void getInput() {
    for(int i = 0; i < NUM; i++) {
        fin >> wheels[i].speed >> wheels[i].n;
        for(int j = 0; j < wheels[i].n; j++) {
            fin >> wheels[i].start[j] >> wheels[i].extent[j];
        }
        wheels[i].position = 0;  
    }
}


bool isQualifiedState() {
    unsigned int mark[360];
    memset(mark, 0, sizeof(unsigned int) * 360);

    for(int w = 0; w < NUM; w++) {
        unsigned int sign = (0x1 << w);
        for(int hole = 0; hole < wheels[w].n; hole++) {
            int begPosition = wheels[w].position + wheels[w].start[hole];
            for(int i = 0; i <= wheels[w].extent[hole]; i++) {
                int degree = (begPosition + i) % 360;
                mark[degree] |= sign;
            }
        }    
    }

    for(int i = 0; i < 360; i++)
        if(mark[i] == ((0x1 << NUM) - 1)) return true;
    return false;
}

void rotate() {
    for(int i = 0; i < NUM; i++)
        wheels[i].position = (wheels[i].position + wheels[i].speed) % 360;
}

void printMinTime() {
    for(int i = 0; i < 360; i++) {
        if(isQualifiedState()) {
            fout << i << endl;
            return;
        }
        rotate();
    }    
    fout << "none" << endl;
}


int main() {
   assert(fin && fout);
   getInput();
   printMinTime();


   return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值