转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
题意:给出一个图,其中有一些点是出口,现在有一个罪犯有一个警察,各在两个不同的点。其中警察有一个最大速度160,问罪犯最少需要多大的速度,保证能从某个出口逃跑。
http://acm.hdu.edu.cn/showproblem.php?pid=3143
yobobobo给推荐的题,当时和他分析了下,点的个数不多,只有100。
对于答案肯定二分,然后我的想法是,首先预处理出每两个点的最短路径,然后判断可行不可行,结果SB了,最短路径肯定不是一条。
但是再一想,n=100,二分之后还是可以暴力搞的。
由于 各种问题,中途也出现了各种奇葩错误。
我开始求的最短路求的是时间,然后对于每个二分的速度,我都要求一次spfa,果断超时。
然后就假设一个速度,求一次spfa,之后根据比例转换一下。还是各种不能过
其间和yobobobo两份错误代码,对拍,还是发现了错误,然后yobobobo过了,我还在跪。
发现我写的spfa不太好,影响精度,直接spfa两次,从罪犯和警察的起点出现,求出到各个点的最短路径长度。这样就是整数,而且在之后的判断中,可以把除法优化成乘法,确保了精度问题。
当中有一步,是可以通过所有点预处理一下,罪犯的速度上界,yobobobo的做法是首先跑一遍bfs或者spfa判断是否可行。也就 是罪犯一定能逃脱的前提是存在一条路径,不经过警察的起点,能到达终点,因为罪犯的速度可以为正无穷。
但是我还是各种WA,找了yobobobo对拍了数据,各种姿势调整后,终于过了,而且还测了各种其它姿势。
注意的地方:
1、对于无解可以spfa或者bfs判断一下,上面提出的有解的必要条件肯定没问题
2、对于罪犯对整个图的最短路,需要注意的是不能经过警察的起点
3、在二分速度之后,判断可以bfs,或者dfs,便是判断可以走到哪些点,条件就是罪犯到达的时间早于警察到达的时间,如果可以则扩展,注意的是每个点只需要判断一次,不需要像DFS那样恢复现场
4、这题的精度要求是1e-6,可是sample给的精度很高,误导了yobobobo,搞得我们都用了1e-10,其实姿势正确1e-6就能过,原以为样例小数据都能这么大误差,所以把精度控制地很严,导致多次TLE
PS:spfa写错好几个地方 ,SB到极点
#include<iostream> #include<cstdio> #include<map> #include<cstring> #include<cmath> #include<vector> #include<algorithm> #include<set> #include<string> #include<queue> #define inf 1600005 #define M 40 #define N 200005 #define maxn 300005 #define eps 1e-7 #define zero(a) fabs(a)<eps #define Min(a,b) ((a)<(b)?(a):(b)) #define Max(a,b) ((a)>(b)?(a):(b)) #define pb(a) push_back(a) #define mp(a,b) make_pair(a,b) #define mem(a,b) memset(a,b,sizeof(a)) #define LL unsigned long long #define MOD 2012 #define lson step<<1 #define rson step<<1|1 #define sqr(a) ((a)*(a)) #define Key_value ch[ch[root][1]][0] #define test puts("OK"); #define pi acos(-1.0) #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; struct Edge{ int v,w,next; }e[100005]; int start[105],tot; bool ext[105]; int p1,p2; int n,m,ee; int a[105][105]; int police[105],pep[105]; void add(int u,int v,int w){ e[tot].v=v;e[tot].w=w;e[tot].next=start[u]; start[u]=tot++; } bool mark; bool vis[105]; double v_p,v_o=160; void dfs(int u,int pre){ if(mark) return; if(police[u]*v_p<=pep[u]*v_o) return ; vis[u]=true; if(ext[u]) {mark=true;return;} for(int i=start[u];i!=-1;i=e[i].next){ int v=e[i].v; if(v==pre||vis[v]) continue; dfs(v,u); if(mark) return ; } } bool check(double vv){ mark=false; v_p=vv; mem(vis,false); dfs(p1,0); return mark; } void slove(){ double low=0,mid,high=0; for(int i=1;i<=n;i++){ if(!police[i]) continue; high=max(high,(double)pep[i]*v_o/police[i]); } high+=2*eps; double ans=-1; while(low+eps<high){ mid=(low+high)/2; if(check(mid)){ ans=mid; high=mid; } else low=mid; } if(ans<0) puts("IMPOSSIBLE"); else printf("%.10f\n",ans); } void Spfa(int s,int *dist){ queue<int>que; while(!que.empty()) que.pop(); bool flag[105];mem(flag,false); for(int i=1;i<=n;i++) dist[i]=inf; dist[s]=0;flag[s]=true; que.push(s); while(!que.empty()){ int u=que.front(); flag[u]=false; que.pop(); for(int i=start[u];i!=-1;i=e[i].next){ int v=e[i].v,w=e[i].w; if(v==p2) continue; int tmp=dist[u]+w; if(tmp<dist[v]){ dist[v]=tmp; if(!flag[v]){ que.push(v); flag[v]=true; } } } } } int main(){ //freopen("in.in","r",stdin); //freopen("out.out","w",stdout); while(scanf("%d%d%d",&n,&m,&ee)!=EOF){ for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) a[i][j]=inf; tot=0;mem(start,-1); while(m--){ int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w);add(v,u,w); } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(a[i][j]<inf) add(i,j,a[i][j]); mem(ext,false); for(int i=0;i<ee;i++){ int k; scanf("%d",&k); ext[k]=true; } scanf("%d%d",&p1,&p2); Spfa(p1,pep); Spfa(p2,police); slove(); } return 0; }