CodeForces 385D: Bear and Floodlight

类型:DP,计算几何
题意:坐标系上有(l,0)~(r,0)一条直线,是一条路。然后还有其他一些点,这些点上有灯,灯能照一定的角度,需要用这些灯照亮那条路,问起点开始最远一直能照到哪。

思路:

状态压缩DP.

dp[1111..1] = max(遍历所有灯,那个被去掉的灯,从dp[11..0..11]这点开始照,最远照到哪)

就是求计算几何有点不会诶。。。。

与出现顺序有关的问题,可以用状态DP,从N!降到2N

我的代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define N 22
const double eps = 1e-8;
const double PI = acos(-1);

double dp[1<<21];
int x[N], y[N], a[N];
int n, l, r;
struct Point {
    Point(){}
    Point(double a,double b):x(a),y(b){}
    double x, y;
    Point operator - (const Point &b) const {
        return Point(x-b.x, y-b.y);
    }
    void print(char str[]) {
        printf("%s %lf %lf
",str, x, y);
    }
}point[N];

Point rotate (Point p, double a) const {
    a = a/180.0 * PI;
    return Point(p.x*cos(a) - p.y*sin(a), p.x*sin(a) + p.y*cos(a));
}

double cal(double now, int i) {
    //printf("i = %d ", i);
    //printf("now = %lf
", now);
    Point to = Point(now, 0) - point[i];
    to = to.rotate(a[i]);
    //printf("to = (%lf,%lf)
", to.x, to.y);
    if (to.y > -eps) return r;
    else return min(point[i].x + point[i].y * (to.x / -to.y), r+0.0);
}

int main() {
    while (~scanf("%d%d%d", &n, &l, &r)) {
        for (int i = 0; i < n; i++)  {
            scanf("%lf%lf%d", &point[i].x, &point[i].y, &a[i]);
            //printf("%lf %lf %d
",point[i].x, point[i].y, a[i]);
        }
        dp[0] = l;
        for (int i = 1; i < (1<<n); i++) {
            dp[i] = l;
            for (int j = 0; j < n; j++) {
                if ((i&(1<<j))) {
                    dp[i] = max(dp[i], cal(dp[(i&(~(1<<j)))], j));
                }
            }
            //printf("%d: %lf
", i, dp[i]);
        }
        printf("%.8lf
", dp[(1<<n)-1]-l);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/shinecheng/p/3583433.html