版权声明:本文为蒟蒻原创文章,转载请注明出处哦~ https://blog.csdn.net/a54665sdgf/article/details/83243494
题目大意:平面上有n只老鼠,每个老鼠都有自己的坐标x,y,以及遁地的时间s。有一只猫在原点,能以一定的速度移动,但每吃掉一只老鼠,其速度就会按一定比率m减小。问这只猫要想在老鼠遁地之前吃掉所有的老鼠,至少需要多大的初始速度。
解法:二分枚举初始速度,则问题转化成了经典的旅行商问题,然后以类似求最短路的方法状压dp求解是否能够吃光所有老鼠即可。状态转移方程为dp[S][pos]=min{dp[S^pos][i]+dis(i,pos)},S代表已吃的老鼠集合,pos代表当前位置,dis(i,pos)代表从i到pos的欧氏距离。
这道题状压dp很好想,但二分不是很好想。由于我的二分比较薄弱,所以就顺势把这道题补上了。
#include<bits/stdc++.h>
using namespace std;
const int N=15+2;
const double eps=1e-5;
double d[1<<N][N],inq[1<<N][N],bi[1<<N],dis[N][N];
double x[N],y[N],s[N];
double m;
int n;
double DIS(int a,int b)
{
return sqrt(pow(x[a]-x[b],2)+pow(y[a]-y[b],2));
}
void pre()
{
for(int S=0; S<(1<<n); ++S)bi[S]=pow(m,__builtin_popcount(S));
for(int i=0; i<n; ++i)
for(int j=0; j<n; ++j)
dis[i][j]=DIS(i,j);
}
struct node
{
int S,pos;
node(int S,int pos):S(S),pos(pos){}
};
bool solve(double v)
{
memset(d,100,sizeof d);
memset(inq,0,sizeof inq);
queue<node> q;
q.push(node(0,0));
memset(d[0],0,sizeof d[0]);
while(!q.empty())
{
int S=q.front().S,pos=q.front().pos;
q.pop(),inq[S][pos]=0;
for(int i=0;i<n;++i)if(!(S&(1<<i)))
{
int S2=S^(1<<i);
double tmp;
if(!S)tmp=sqrt(pow(x[i],2)+pow(y[i],2))/v;
else tmp=d[S][pos]+dis[pos][i]/(v*bi[S]);
if(tmp<=s[i])
{
d[S2][i]=min(d[S2][i],tmp);
if(!inq[S2][i])inq[S2][i]=1,q.push(node(S2,i));
}
}
}
double ans=1e11;
for(int i=0;i<n;++i)ans=min(ans,d[(1<<n)-1][i]);
return ans<1e10;
}
int main()
{
scanf("%d",&n);
for(int i=0; i<n; ++i)scanf("%lf%lf%lf",&x[i],&y[i],&s[i]);
scanf("%lf",&m);
pre();
double l=0,r=99999999;
for(int i=0;i<50;++i)
{
double mid=(l+r)/2.0;
solve(mid)?r=mid:l=mid;
}
printf("%f\n",l);
return 0;
}