The BCCB (Bangladesh Cricket Control Board) has decided to build a new international cricket stadiumin Barisal. It will be convex in shape unlike others. Floodlight will be placed outside the stadium sothat play is possible under light. Each floodlight covers a particular part of the stadium. A side of thestadium is covered by a floodlight if the normal on the side makes an acute angle with the light rays.
In the above figure stadium ABCDEF can be covered by two different sets of lights. It takes certaincost to build each floodlight. There are several options to choose the set of lights. In this problem youwill have to find the minimum cost to cover the stadium completely. A stadium is completely coveredif all of its sides is covered by at least one floodlight.
Input
Each input set starts with a positive integerN which denotes the number of sides in the stadium. Itwill be in the range between 3 to 30. In next few lines the coordinates of the vertices will be given inanticlockwise order. Next line will contain another integer M(1 ≤M ≤1000) denoting the numberof light positions. In next few lines there will be 3Mintegers in the format x y cwhere (x,y) is thecoordinates of the position andc (a positive integer) is the cost to build the floodlight in that position.All light positions will be strictly outside the stadium. The absolute value of each coordinate will notexceed 10000 and the cost to build a floodlight will be at most 10000000.
Input is terminated by a case whereN = 0. This case should not be processed.
Output
For each input set print in a line the minimum cost to build the floodlights. If it is not possible to coverthe stadium completely, then print ‘Impossible.’
Sample Input
3
00
10 0
0 10
3
-1 -1 1011 -1 10-1 11 103
00
10 0
0 10
3
-1 -1 1011 -1 10-1 12 100
Sample Output
Impossible. 20
题意:
输入一个凸n边形体育馆和多边形外n个点光源,每个点光源有一个费用值。选择一组点光源,照亮整个多边形,使得费用值综合尽量小。
分析:
看的时候觉得DP方程应该还是挺简单的,处理每个光源照了哪几条边是问题。在网上查了几份代码以后发现有检测n边形内一点与该光源位于某条边两端,则该条边被照射,觉得很有道理,但是想了半天不知道怎么实现,觉得有点繁琐。又看到有大神代码是判断锐角,想到题目条件说的锐角以为按题所说判断就好,结果大概是我读错题了其实大神判断的是逆时针方向相邻两点与光源之间的两条连线角度是否是逆时针旋转,如果是,很明显该边是可以被照射的。
之后就是dp方程,看起来好像很普通有点不一样,其实就是普通的决策,点的数量很小,用近乎暴力的状态转移方程解决。
主要借鉴了http://blog.csdn.net/accelerator_/article/details/25117155
#include <algorithm> #include <iostream> #include <sstream> #include <cstring> #include <cstdlib> #include <string> #include <vector> #include <cstdio> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> using namespace std; #define INF 0x3f3f3f3f const int N=105; const int mod=1e9+7; int dp[N],flag[N],n,m; struct Point { double x,y; Point (double xx=0,double yy=0) {x=xx;y=yy;} void read() { scanf("%lf%lf",&x,&y); } } p[N]; struct Q { int l,r,c; } q[10*N]; bool judge(Point p0,Point p1,Point p2) { return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y)<0; } Q tra(Point t, int c) { Q ans; ans.c=c; memset(flag, 0, sizeof(flag)); for (int i=0; i<n; i++) { if (judge(t, p[i], p[i+1])) { flag[i]=true; } } if (flag[0]&&flag[n-1]) { int l=n-1,r=n; while (flag[l-1]) l--; while (flag[r-n+1]) r++; ans.l=l; ans.r=r; } else { int l=0,r=n-1; while (!flag[l]) l++; while (!flag[r]) r--; ans.l=l; ans.r=r; } return ans; } int main() { while (cin>>n&&n) { for (int i=0; i<n; i++) { p[i].read(); } p[n]=p[0]; Point temp; int c; cin>>m; for (int i=0; i<m; i++) { temp.read(); scanf("%d",&c); q[i]=tra(temp, c); } int ans=INF; for (int i=0; i<n; i++) { memset(dp, INF, sizeof(dp)); dp[i]=0; for (int j=0; j<n; j++) { int r=i+j; for (int k=0; k<m; k++) { if (q[k].l>r) continue; int now=min(i+n,q[k].r+1); dp[now]=min(dp[now], dp[r]+q[k].c); } } ans=min(ans, dp[i+n]); } if (ans==INF) cout<<"Impossible.\n"; else cout<<ans<<endl; } return 0; }