动态规划,同时又涉及到几何的一些知识。首先对于输入的那些顶点数据求出对应的多边形的中心,然后利用叉乘的符号判断对应的光源的点是否能够照射到对应的边,判断完所有的边之后就记录该光源点能够照射的范围,这里出现了一个技巧在于由于这个多边形是环状的,但是我们在处理环形的时候是把多边形的边数变为原来的两倍,也就是说,多边形的边的实际编号为0到N-1,从后面开始,N就代表着第0条边,N+1就代表着第1条边,以此类推,这样做是为了便于后面动态规划的处理。
在上面的处理全部都结束的时候,我们分别从第1条边一直到第N条边开始进行动态规划的操作,从当前的边i开始,偏移j作为起始边,判断是否能够有光源照到当前的起始边,如果可以就对最后能照到的那条边的代价之和进行更新,并且要记录所有情况的最优值,具体实现见如下代码:
#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<sstream>
#include<cstdio>
#include<deque>
using namespace std;
const double eps = 1e-6;
const int Inf = 1<<30;
class Point{
public:
double x, y;
int left, right;//供light使用
int cost;
Point(double x = 0, double y = 0, int cost = 0){
this->x = x;
this->y = y;
this->cost = cost;
}
Point Sub(Point a){
return Point(x - a.x, y - a.y);
}
double mulCross(Point a){
return (x*a.y-y*a.x);
}
};
Point center;//多边形的中心点
class Solve{
public:
int N, M;//多边形的顶点个数 光源的个数
Point vert[35];
Point light[1010];
int ans;
int judge(double t1,double t2){
if (t1*t2 < -eps) return -1;
return t1*t2 > eps;
}
void getEdge(int ind){
bool flag[35];
memset(flag, false, sizeof(flag));
for (int i = 0; i < N; i++){
Point ab = vert[i + 1].Sub(vert[i]);
Point ao = center.Sub(vert[i]);
Point ai = light[ind].Sub(vert[i]);
double t1 = ab.mulCross(ao);
double t2 = ab.mulCross(ai);
if (judge(t1, t2) < 0) flag[i] = true;
}
if (flag[0] && flag[N - 1]){
int left = N - 1, right = N;
while (flag[left]){
light[ind].left = left;
left--;
}
while (flag[right-N]){
light[ind].right = right;
right++;
}
}
else{
int left = 0, right = N - 1;
while (!flag[left]) left++;
light[ind].left = left;
while (!flag[right]) right--;
light[ind].right = right;
}
light[ind].right++;//左闭右开
if (light[ind].right < light[ind].left)
light[ind].right += N;
}
void Deal(){
for (int i = 0; i < M; i++)
getEdge(i);
ans = Inf;
int dp[70];
for (int i = 0; i < N; i++){
for (int m = 0; m < 70; m++) dp[m] = Inf;
dp[i] = 0;
for (int j = 0; j < N; j++){
int t = i + j;
for (int k = 0; k < M; k++){
if (light[k].left > t) continue;
int ind = min(light[k].right, i + N);
dp[ind] = min(dp[ind], light[k].cost + dp[t]);
}
}
ans = min(ans, dp[i + N]);
}
if (ans == Inf) cout << "Impossible.\n";
else cout << ans << endl;
}
};
int main(){
Solve a;
while (cin >> a.N){
if (a.N == 0) break;
center.x = center.y = 0;
for (int i = 0; i < a.N; i++){
cin >> a.vert[i].x >> a.vert[i].y;
center.x += a.vert[i].x;
center.y += a.vert[i].y;
}
a.vert[a.N] = a.vert[0];
center.x = center.x / a.N;
center.y = center.y / a.N;
cin >> a.M;
for (int i = 0; i < a.M; i++)
cin >> a.light[i].x >> a.light[i].y >> a.light[i].cost;
a.Deal();
}
return 0;
}