题目来源: http://poj.org/problem?id=3347
题意:变长不同的n个正方形,斜45度按顺序平放在坐标轴上,尽量靠左但不能跃出x=0,问从上往下看,哪些正方形是可见的。
题解:1、假如前i-1个正方形位置都确定了,那么可以让第i个正方形与前i-1个正方形每个都计算一次它如果和它相依靠的话左边顶点坐标的值,然后取一个最大的便是这个正方形的左端点位置。 这个结论 需要仔细推敲。
2、对于j<i的正方形,如果i的边长大于j那么j的最右能看到的部分就不会比i的最左端点大,反之,i的最左能看到的部分就不会比j最右端点小。
3、通过第2步筛选,将那些最左能看到的端点比最右能看到端点大或等于的去掉,剩下的就是所要求的。
4: 注意 ,我们 存放 正方形 端点的坐标时, 是将坐标轴 扩大 √2 倍。
代码如下:
#include <iostream> #include <algorithm> #include <stdlib.h> #include <iostream> #include <stdio.h> #include <string> #include <string.h> #include <vector> #include <set> #include <math.h> #include <cmath> #include <map> #include <queue> using namespace std; typedef long long ll; const int N =60; struct Line { int left; int right; int length; }; int n; Line line[N]; int side[N]; void solve() { } int main() { while(cin>>n && n) { cin>>side[0]; line[0].left=0; line[0].right=2*side[0]; // 坐标轴 扩大 √2 倍 line[0].length=2*side[0]; for (int i=1;i<n ;i++) { cin>> side[i]; int left=0; for(int j=i-1 ;j>=0; j--) left=max(left, line[j].right-abs(side[i]-side[j]) ); // 第i 个 正方形的左端点的 x位置 是 与 前 i-1 个正方形依靠的 最大 x 值 line[i].left=left; line[i].right=line[i].left+2*side[i]; line[i].length=2*side[i]; } for(int i=1 ;i<n;i++) { for(int j=0; j<i;j++) { if(line[i].length < line[j].length && line[i].left < line[j].right) // 更新左右端点的值 line[i].left=line[j].right; if(line[i].length > line[j]. length && line[i].left < line[j].right ) line[j].right=line[i].left; } } int count=0; for(int i=0 ;i<n ;i++) { if(line[i].left < line[i].right) { if(count) printf(" "); printf("%d",i+1); count=1; } } printf(" "); } return 0; }