UVA-10641 Barisal Stadium (DP+几何)

20 篇文章 0 订阅
2 篇文章 0 订阅

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;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值