题目链接:http://poj.org/problem?id=3347
题意:给予n个正方形,要求45°角放置,最左边的正方形紧贴Y轴,所有的正方形的下面的端点都在X轴上。然后按照正方形不能交错但要尽可能的挨着的原则,摆放,最后输出从上往下看能看到的正方形的编号。正方形必须要按照顺序摆放。
参考博客:http://www.cnblogs.com/tmeteorj/archive/2012/10/19/2731024.html
题解:1、假如前i-1个正方形位置都确定了,那么可以让第i个正方形与前i-1个正方形每个都计算一次它如果和它相依靠的话左边坐标的值,然后取一个最大的便是这个正方形的左端点位置。
2、对于j<i的正方形,如果i的边长大于j那么j的最右能看到的部分就不会比i的最左端点大,反之,i的最左能看到的部分就不会比j最右端点小。
3、通过第2步筛选,将那些最左能看到的端点比最右能看到端点大或等于的去掉,剩下的就是所要求的。
注意最后的精度问题,开始把所有长度乘以sqrt(2)应该就可以避免精度问题。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const double eps = 1e-8;
struct m {
double len, l, r;
};
m sq[55];
int main() {
int n;
while(~scanf("%d", &n) , n) {
int i, j;
for(i = 1; i <= n; i++) {
scanf("%lf", &sq[i].len);
sq[i].l = 0;
for(j = 1; j < i; j++) {
sq[i].l = max(sq[i].l, sq[j].r - fabs(sq[i].len - sq[j].len) / sqrt(2.0));
}
sq[i].r = sq[i].l + sq[i].len * sqrt(2.0);
}
//更新所有正方形的可见左右端点。因为并不知道每个正方形的相对位置,所以直接遍历一遍即可
for(i = 1; i <= n; i++) {
for(j = 1; j < i; j++) {
if(sq[i].len > sq[j].len && sq[i].l < sq[j].r) sq[j].r = sq[i].l;
if(sq[i].len < sq[j].len && sq[i].l < sq[j].r) sq[i].l = sq[j].r;
}
}
int flag = 1;
for(i = 1; i <= n; i++) {
if(sq[i].l < sq[i].r - eps) { //精度问题,不加eps会wa
if(flag) flag = 0;
else printf(" ");
printf("%d", i);
}
}
puts("");
}
return 0;
}