题目大意:
给出一个图,其中有一些点是出口,现在有一个罪犯有一个警察,各在两个不同的点。其中警察有一个最大速度160,问罪犯最少需要多大的速度,保证能从某个出口逃跑。
一开始看了题目没什么感觉,当将题目看了两三遍后就发现只要到某一个点罪犯用的时间比警察的少则在那个点不会被抓,很显然,到某一个点会走最短路径。所以要用到两次最短路算法,二分罪犯车子的速度,然后搜索在当前速度下是否可以逃脱。
注意的地方:
1、对于无解可以spfa或者bfs判断一下,上面提出的有解的必要条件肯定没问题
2、对于罪犯对整个图的最短路,需要注意的是不能经过警察的起点
3、在二分速度之后,判断可以bfs,或者dfs,便是判断可以走到哪些点,条件就是罪犯到达的时间早于警察到达的时间,如果可以则扩展,注意的是每个点只需要判断一次,不需要像DFS那样恢复现场
4、这题的精度要求是1e-6,可是sample给的精度很高,搞得我们都用了1e-10,其实姿势正确1e-6就能过,原以为样例小数据都能这么大误差,所以把精度控制地很严,导致多次TLE
PS:spfa写错好几个地方 ,SB到极点
#include <iostream>
#include <cstdio>
#include <climits>
#include <cstring>
#include <queue>
using namespace std;
const int maxn = 110;
const int inf = 1600005;
int map[maxn][maxn],Exit[maxn];
int dis1[maxn],dis2[maxn],vis[maxn];
double ptime[maxn];
int n,m,e,b,p;
struct node
{
int v,len,next;
}edge[maxn*maxn];
int head[maxn],id;
void add_edge(int u,int v,int len)
{
edge[id].v = v;edge[id].len = len; edge[id].next = head[u];head[u] = id++;
edge[id].v = u;edge[id].len = len; edge[id].next = head[v];head[v] = id++;
}
inline double max(double x,double y)
{
return x > y ? x : y;
}
void spfa(int s,int dis[])
{
for(int i = 0; i <= n; i++)dis[i] = inf;
memset(vis,0,sizeof(vis));
queue<int>que;
int now,tmp;
dis[s] = 0;
vis[s] = 1;
que.push(s);
while( !que.empty())
{
int u = que.front();
que.pop();
vis[u] = 0;
for( int id = head[u]; id != -1; id = edge[id].next)
{
int v = edge[id].v;
if( v == p)continue;
if( dis[v] > dis[u] + edge[id].len)
{
dis[v] = dis[u] + edge[id].len;
if( !vis[v])
{
vis[v] = 1;
que.push(v);
}
}
}
}
}
bool dfs(int u,double speed)
{
if( Exit[u] )return true;
for(int id = head[u]; id != -1; id = edge[id].next)
{
int v = edge[id].v;
if( !vis[v] && dis1[v]*1.0*160 < dis2[v]*speed)
{
vis[v] = 1;
if( dfs(v,speed) )
return true;
}
}
return false;
}
void slove()
{
double l = 0,r = 0,m;
for(int i=1;i<=n;i++)
{
if(!dis2[i] ) continue;
r=max(r,(double)dis1[i]*160/dis2[i]);
}
double ans = -1;
r += 2*(1e-7);
while( r - l > 1e-7)
{
m = (l+r)*0.5;
memset(vis,0,sizeof( vis ));
if(dfs(b,m))
{
r = m;
ans = m;
}
else l = m;
}
if( ans < 0)puts("IMPOSSIBLE");
else
printf("%.10lf\n",ans);
}
int main()
{
int i,j,u,v,len;
while( scanf("%d%d%d",&n,&m,&e) != EOF)
{
memset(head,-1,sizeof(head));
id = 0;
while( m -- )
{
scanf("%d%d%d",&u,&v,&len);
add_edge(u,v,len);
}
memset(Exit,0,sizeof(Exit));
for( i = 0; i < e; i++)
{
scanf("%d",&u);
Exit[u] = 1;
}
scanf("%d%d",&b,&p);
spfa(b,dis1);
spfa(p,dis2);
slove();
}
return 0;
}
/*
3 2 1
1 2 7
2 3 8
1
3 2
3 2 1
1 2 7
2 3 8
1
2 3
4 4 2
1 4 1
1 3 4
3 4 10
2 3 30
1 2
3 4
*/