zoj 3580 angry birds 愤怒的小鸟(zoj 的题目就是与时俱进啊)

Angry Birds

Time Limit: 4 Seconds       Memory Limit: 65536 KB

In the famous game Angry Birds, players can choose a direction to shoot a blue bird, which can be spilt into three birds to hit those annoying pigs or wood boards. Birds flies in parabola with gravity constant g=9.8m/s2.

This time, Paopao is commanding her birds to break wood boards on the ground following these rules:

  • Birds are shooted in the starting position (0,Y).
  • Birds' initial speed is fixed as V. However, her direction can be arbitrarily determined by Paopao.
  • Each Bird can be spilt into three birds in the starting position. Assuming the angle of the orign direction vector is p, the angles after spilting is p-pi/12p, and p+pi/12(in Radian). Three birds share the same initial speed V. Notice that there is a ceiling with y=Y, that is to say, any birds flying above the starting position will disappear instantly.
  • Wood boards are placed on the ground (the y-axis of ground is 0). The thickness of each board can be ignored and each board can be regarded as a simple line with cordinates (x1,0)-(x2,0). Once hit by a bird, the board will disappear. Hitting on the boundary of the board won't break the board and no boards will overlap each other.

Apparently, some boards can be destroyed in the same time with one shoot. Paopao wants to know the least number of shoots she need to destroy all boards.

Input

The problem contains multiple cases.

Each case starts with one integer and two real numbers indicating the number of boards n (1 ≤ n ≤ 16), the initial speed V (0 < V ≤ 1000), and Y (0 < Y ≤ 1000).

The following n lines each contains two real numbers x1x2 (0 ≤ x1 < x2 ≤ 1000000), describing the cordinates of a board.

Process to the end of file.

Output

For each test case, output the least number of shoots needed to eliminate all boards in a single line. If some board cannot be broken, output -1 instead.

Sample Input

2 1.0 1.0
0 0.0001
0.45 0.45001
3 1.0 1.0
0 0.0001
0.45 0.45001
0.5 0.6

Sample Output

2
-1



稍作预处理然后 bitmask dp



#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

//#undef _DEBUG

#ifdef _DEBUG
#define debug_printf(...) printf(__VA_ARGS__)
#else
#define debug_printf(...)
#endif

int n;
double V;
double Y;

const int MAXN = 16;

struct Bridge
{
    double x0;
    double x1;
};

Bridge bridge[MAXN];
int bridges;

void get()
{
	if (scanf ("%d%lf%lf", &n, &V, &Y) == EOF) {
		exit(0);
	}

	for (int i=0; i<n; ++i) {
		scanf ("%lf%lf", &bridge[i].x0, &bridge[i].x1);
		if (bridge[i].x0 > bridge[i].x1) {
			swap (bridge[i].x0, bridge[i].x1);
		}
	}

	bridges = n;
}

struct Shoot
{
	double angle;
    int hitsBridge;
};

bool isDoubleEqual (double, double);

const double PI = 3.141592653589793;

const double ESP = 1e-7;

const double g = 9.8;

const double SHOOT_ANGLE_OFFSET = ESP / 100;

const int INF = 100000;

bool isDoubleEqual (double x, double y)
{
	return fabs (x - y) < ESP;
}

double flyingTime (double virticalVelocity)
{
	double v = virticalVelocity;
	double ret = (-v + sqrt (v * v + 2.0 * g * Y)) / g;
	return ret;
}

double flyingDistance (double angle)
{
	double ret = V * cos (angle) * flyingTime (V * sin (angle));
	return ret;
}

double angle (double x)
{
	double lo = 0.0;
	double hi = PI / 2.0;

	if (flyingDistance (lo) < x) {
		return PI * 2.0;
	}

	while (fabs (lo - hi) >= ESP / 100) {
		double m = (lo + hi) / 2.0;
		if (flyingDistance (m) < x) {
			hi = m;
		} else {
			lo = m;
		}
	}

	return lo;
}

Shoot shoot[MAXN * 6];
int shoots;

double dAngle[3] = {-PI / 12.0, 0.0, PI / 12.0};

void print_shoots (bool printHitsBridge)
{
	debug_printf ("\n%d shoots:\n", shoots);
	for (int s=0; s<shoots; ++s) {
		debug_printf ("ang: %.6lf", shoot[s].angle);
		if (printHitsBridge) {
            for (int b=0; b<bridges; ++b) {
                if ((1 << b) & shoot[s].hitsBridge) {
                    debug_printf (" %d", b);
                }
            }
		}
		debug_printf ("\n");
	}
}

void makeShoots()
{
	debug_printf ("\n%d bridges:\n", bridges);
	for (int i=0; i<bridges; ++i) {
		debug_printf ("(%.6lf, %.6lf)\n", bridge[i].x0, bridge[i].x1);
	}

	shoots = 0;
	for (int i=0; i<bridges; ++i) {
		for (int a=0; a<3; ++a) {
			shoot[shoots++].angle = angle (bridge[i].x0) + dAngle[a] - SHOOT_ANGLE_OFFSET;
		}

		for (int a=0; a<3; ++a) {
			shoot[shoots++].angle = angle (bridge[i].x1) + dAngle[a] + SHOOT_ANGLE_OFFSET;
		}
	}

    for (int i=0; i<shoots; ++i) {
        shoot[i].hitsBridge = 0;
    }

	for (int s=0; s<shoots; ++s) {
		for (int a=0; a<3; ++a) {

			debug_printf ("s = %d, a = %d\n", s, a);

			double ang = shoot[s].angle + dAngle[a];

			if (ang < 0 || PI / 2.0 < ang) {
				continue;
			}

			double fd = flyingDistance (ang);
			debug_printf ("flyingDistance (%.6lf) == %.6lf\n", ang, fd);

			for (int b=0; b<bridges; ++b) {
				if (bridge[b].x0 <= fd && fd <= bridge[b].x1) {
                    shoot[s].hitsBridge |= (1 << b);
				}
			} // for all bridges

		} // for 3 angles
	} // for all shoots

    // remove unsignificant shoots
	for (int s=0; s<shoots; ++s) {
        if (shoot[s].hitsBridge == 0) {
			debug_printf ("shoot[%d]: angle = %.6lf, hits no bridge\n", s, shoot[s].angle);
			swap (shoot[s], shoot[shoots - 1]);
			--shoots;
			--s;
		}
	}

	print_shoots (true);
}

bool bridgeBroken[MAXN];

int dp[1 << MAXN];

int minShoots (int bridgeMask)
{
    if (dp[bridgeMask] != -1) {
        return dp[bridgeMask];
    }

    if (bridgeMask == 0) {
        return dp[bridgeMask] = 0;
    }

    dp[bridgeMask] = INF;

    for (int s=0; s<shoots; ++s) {
        int nextBridgeMask = bridgeMask & ~shoot[s].hitsBridge;
        if (nextBridgeMask != bridgeMask) {
            int nextMinShoots = minShoots (nextBridgeMask);
            if (nextMinShoots + 1 < dp[bridgeMask]) {
                dp[bridgeMask] = nextMinShoots + 1;
            }
        }
    }

    return dp[bridgeMask];
}

int main (int argc, char **argv)
{
	while (true) {
		get();
		makeShoots();
        memset (dp, -1, sizeof (dp));
        int ans = minShoots ((1 << n) - 1);
        if (ans >= INF) {
            printf ("-1\n");
        } else {
            printf ("%d\n", ans);
        }
	}

	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值