uva 618 - Doing Windows(暴力+数学)

题目链接:uva 618 - Doing Windows


题目大意:给出电脑桌面的大小W和H,现在在桌面上有4个窗口,给出窗口的初始大小,问说能不能通过调整各个窗口的大小(长宽比例不能变)使得4个屏幕刚好占满整个屏幕,并且互相不覆盖。


解题思路:其实可以直接暴力出所有情况,不过细节比较多,而且要考虑所有的细节。

我的做法的是先将4个窗口缩小至最小的状态,然后枚举左下角的窗口,

有四种可能

uva 618 - Doing Windows(暴力+数学)_第1张图片uva 618 - Doing Windows(暴力+数学)_第2张图片

蓝色部分为另外枚举的窗口,3,4种情况要分别保证说长、宽相等,然后S部分就是子问题。

所以用一个二进制数来表示窗口被使用的情况,然后如果只剩一块,看随后一块和剩下的矩形长宽是否成比例。

#include <cstdio>
#include <cstring>

const int N = 5;
typedef long long ll;

inline ll gcd (ll a, ll b) {
	return b == 0 ? a : gcd(b, a%b);
}

inline int bitCount(int x) {
	return x == 0 ? 0 : bitCount(x/2) + (x&1);
}

struct state {
	ll r, c;
	state (ll r = 0, ll c = 0) {
		this->r = r;
		this->c = c;
	}
	void get() {
		scanf("%lld%lld", &r, &c);
		ll d = gcd(r, c);
		r /= d;
		c /= d;
	}
}w[N];

bool solve (ll R, ll C, int s);

inline bool cmp (state a, state b) {
	return a.r * b.c == b.r * a.c;
}

void cat (state u, state v, state& a, state& b, int s) {
	ll p, q;
	if (s == 0) {
		ll d = gcd(u.r, v.r);
		p = v.r / d;
		q = u.r / d;
	} else {
		ll d = gcd(u.c, v.c);
		p = v.c / d;
		q = u.c / d;
	}
	a.r = u.r * p;
	a.c = u.c * p;
	b.r = v.r * q;
	b.c = v.c * q;
}

bool judge(ll R, ll C, state v, int s, int sign) {

	if (sign == 0) {

		if (R % v.r)
			return false;

		ll k = R / v.r;
		C -= v.c * k;
		if (C <= 0)
			return false;
	} else {

		if (C % v.c)
			return false;
		
		ll k = C / v.c;
		R -= v.r * k;
		if (R <= 0)
			return false;

	}
	return solve(R, C, s);
}

bool judgeTow(ll R, ll C, state v, int s) {

	for (int i = 0; i < 4; i++) {
		if ((s&(1<<i)) == 0) 
			continue;

		state add, a, b;
		for (int j = 0; j < 2; j++) {
			cat(v, w[i], a, b, j);

			if (j == 0) {
				add.r = a.r;
				add.c = a.c + b.c;
			} else {
				add.r = a.r + b.r;
				add.c = a.c;
			}

			if (judge(R, C, add, s-(1<<i), 1-j))
				return true;
		}
	}
	return false;
}

bool solve (ll R, ll C, int s) {

	int cnt = bitCount(s);

	if (cnt == 1) {

		for (int i = 0; i < 4; i++)
			if (s&(1<<i))
				return cmp(state(R, C), w[i]);
	}

	for (int i = 0; i < 4; i++) {
		if ((s&(1<<i)) == 0)
			continue;

		for (int j = 0; j < 2; j++) {
			if (judge(R, C, w[i], s-(1<<i), j))
				return true;
		}

		if (cnt > 2 && judgeTow(R, C, w[i], s-(1<<i)))
			return true;
	}
	return false;
}

int main () {
	int cas = 1;
	ll R, C;
	while (scanf("%lld%lld", &R, &C) == 2 && R + C) {
		for (int i = 0; i < 4; i++)
			w[i].get();

		printf("Set %d: %s\n", cas++, solve(R, C, 15) ? "Yes" : "No");
	}
	return 0;
}



你可能感兴趣的:(uva 618 - Doing Windows(暴力+数学))