UVA 10413 - Crazy Savages
题意:一个岛上有一些山洞,有n个幸存者,每个幸存者初始在山洞Ci,山洞是形成一个环的,每天每个人都会走Pi,然后Li天后该人会死掉,要求一个最小的山洞数使得每个人在活着的时候都不会碰面(因为碰面就会发生冲突)
思路:枚举山洞数m,然后两两判断会不会碰面
判断的方法是:两个人其实就是两个线性方程
(c1+p1k1)%m=x 和 (c2+p2k2)%m=x 如果两人会在同一天碰面,那么两人k值相同,两式相减后得到(c1−c2)+k(p1−p2)=ym,移项后得到一个线性方程
ax+by=c,a=(p1−p2),b=−m,c=(c2−c1),然后利用扩展欧几里得算法去求解判断有没有解在[0,min(k1, k2)]中,如果有就是会发生冲突,不满足
代码:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
int t, n;
struct People {
int c, p, l;
void read() {
scanf("%d%d%d", &c, &p, &l);
}
} p[20];
bool cmp(People a, People b) {
return a.l > b.l;
}
int exgcd(int a, int b, int &x, int &y) {
if (!b) {x = 1; y = 0; return a;}
int d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
bool judge(People A, People B, int mod) {
int a = A.p - B.p;
int b = -mod;
int c = B.c - A.c;
int x, y;
int d = exgcd(a, b, x, y);
if (c % d) return false;
int down = -INF, up = INF;
int tmp = min(A.l, B.l);
if (b / d < 0) {
down = max(down, (int)ceil((tmp * d - x * c) * 1.0 / b));
up = min(up, (int)floor(-x * c * 1.0 / b));
}
else {
down = max(down, (int)ceil(-x * c * 1.0 / b));
up = min(up, (int)floor((tmp * d - x * c) * 1.0 / b));
}
return down <= up;
}
bool solve(int mod) {
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++)
if (judge(p[i], p[j], mod))
return false;
return true;
}
int main() {
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
int down = 0;
for (int i = 0; i < n; i++) {
p[i].read();
down = max(down, p[i].c);
}
for (int i = down; i <= 1000000; i++) {
if (solve(i)) {
printf("%d\n", i);
break;
}
}
}
return 0;
}