题意:
从坐标(L,0)到坐标(R,0)直线行走 走过的地方必须被N盏灯里的至少1盏照亮 每盏灯有一个位置坐标 照亮方向任意且可照亮无限远 但只有一个固定的照明角度 求最远走多远
思路:
灯的数量只有20 这是突破口 可以状态压缩 用dp[i]表示i状态时走的距离 i的二进制形式中1表示对应灯亮
那么最后答案就是dp[(1<<n)-1]即所有灯全亮 状态转移 dp[i] = max( dp[i] , dp[j] + distance(j->i) )
实现时用bfs维护dp就好 计算distance可能有点麻烦(我分类讨论的) 详见代码func()函数
代码:
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define M 1100000
#define pi acos(-1)
double dp[M];
double u,v;
int qu[M],in[M];
struct light
{
double x,y,dg;
}lt[21];
int n,l,r;
double func(double way,int id)
{
double deg=atan(fabs(way+u-lt[id].x)/lt[id].y);
if(lt[id].x-u>way)
{
if(lt[id].dg<deg)
{
deg=deg-lt[id].dg;
return lt[id].x-u-tan(deg)*lt[id].y-way;
}
else
{
deg=lt[id].dg-deg;
return tan(deg)*lt[id].y+lt[id].x-u-way;
}
}
else
{
if(atan((v-lt[id].x)/lt[id].y)>deg+lt[id].dg)
return tan(lt[id].dg+deg)*lt[id].y-(u+way-lt[id].x);
else return v-u;
}
}
int main()
{
int i,now,to;
scanf("%d%lf%lf",&n,&u,&v);
for(i=0;i<n;i++)
{
scanf("%lf%lf%lf",<[i].x,<[i].y,<[i].dg);
lt[i].dg=lt[i].dg/180*pi;
}
qu[0]=l=r=0;
while(l<=r)
{
now=qu[l++];
for(i=0;i<n;i++)
{
if(!(now&(1<<i)))
{
to=now|(1<<i);
dp[to]=max(dp[to],dp[now]+func(dp[now],i));
if(!in[to])
{
in[to]=1;
qu[++r]=to;
}
}
}
}
//for(i=0;i<(1<<n);i++) printf("%d %f\n",i,dp[i]);
printf("%.9f\n",min(dp[(1<<n)-1],1.0*v-u));
return 0;
}