武大OJ 612. Catch the sheep
Description
Old Sama is a great and powerful magician in the word.
One day, a little girl, Anny, touched Sama’s crystal and broke into his magic 2D space. However, Sama is very amiable. So he wanted to send Anny back to the real world instead of trapping her and he also wanted to teach Anny a lesson ‘Never touch others’ things without asking especially for a great magician’.
So Sama told Anny there were N sheep in the space and each of them was running in a counter clockwise circular motion with a constant speed u, which was less than 1 (Sama is kind, isn’t he?). Only after Anny caught all of the sheep, she could leave.
Anny was scarred and she wanted to leave as soon as possible. Her speed is exactly 1. Now she wondered how soon can she leave?
Input
The input consists of several test cases.
The first line consists of one integer T (T <= 30), meaning the number of test cases.
For each test cases:
The first line consists of integer n (n<=10).
In the next n lines, the i-th line consists of four real number, xi, yi, ri, ui, describing the motion of each sheep (|xi|, |yi| <= 100, 0<=ri<=100, 0<ui<1). (xi, yi) means the coordinate of the center of the circle, ri means the radius of the circle, and ui means the speed of the sheep i.
You should know Anny always started in (0,0). And the sheep always started in (xi+ri, yi).
Output
For each test case, output one line with one real number with 6 decimal places meaning the minimum time Anny could leave without any space.
Sample Input
1 1 11 0 1 0.31415926535897932384626433832795
Sample Output
10.000000
本题的难点是根据当前坐标和时间求与第i只羊的最短交汇时间,转移的耗时显然是满足二分性质的,知道当前位置,当前时刻,下一只羊的信息就能够通过二分求得耗时
状态压缩Dp,dp[status][i]表示抓了status状态表示的羊最后抓的羊的编号为i
其实用爆搜应该也可以
时间复杂度:𝑂(𝑘𝑛^2∗2^𝑛)(k是二分迭代次数)
#include<iostream> #include<stdio.h> #include<math.h> using namespace std; typedef struct{ double x,y,time; bool isCal; }Status; typedef struct{ double x,y,r,u; }Point; Status f[1<<11][10]; Point p[10]; int t,n; Status calcuateTimeAndXY(double x,double y,double time,int num){ double left=0,right=1000,mid; double u=p[num].u; double r=p[num].r; double x0=p[num].x; double y0=p[num].y; double x2,y2; while(fabs(right-left)>1e-9) { mid=(right+left)/2.0; double t=mid+time; double theta=(u*t-floor(u*t/(2*M_PI*r))*2*M_PI*r)/r; x2=x0+r*cos(theta); y2=y0+r*sin(theta); if((x2-x)*(x2-x)+(y2-y)*(y2-y)>mid*mid) left=mid; else right=mid; } Status a; a.x=x2;a.y=y2;a.time=time+mid;a.isCal=true; return a; } void Dp(int state,int num){ if(f[state][num].isCal==true) return ; if(state==0){f[state][num]=calcuateTimeAndXY(0,0,0,num);return ;} double minTime=1e100; for(int i=0;i<n;++i) if((state&(1<<i))!=0) { Dp(state^(1<<i),i); Status tt=calcuateTimeAndXY(f[state^(1<<i)][i].x,f[state^(1<<i)][i].y,f[state^(1<<i)][i].time,num); if(tt.time<minTime) { minTime=tt.time; f[state][num]=tt; } } return ; } int main() { scanf("%d",&t); while(t>0) { t--; scanf("%d",&n); for(int i=0;i<n;++i) scanf("%lf %lf %lf %lf",&p[i].x,&p[i].y,&p[i].r,&p[i].u); for(int i=0;i< 1<<n ;++i) for(int j=0;j<n;++j) f[i][j].isCal=false; double ans=1e100; for(int i=0;i<n;++i) { Dp(((1<<n) -1)^(1<<i),i); if(f[((1<<n) -1)^(1<<i)][i].time<ans) ans=f[((1<<n) -1)^(1<<i)][i].time; } // cout<<f[0][0].time<<" "<<f[0][1].time<<endl; printf("%.6f\n",ans); } }