P8914 [DMOI-R2] 梦境

警示后人,一定要注意是 YES 还是 Yes!!!

最近 Atcoder 的比赛打多了,里面的题基本上是 Yes,然后就导致今天比赛时 WA 的一脸疑惑,wssb。

Solution

关于本题解中变量的有关说明:\(d?\) 代表源点为 \(?\) 的单源最短路,如 \(ds\) 代表以 \(s\) 为源点的最短路。原题中的 \(F\) 在代码中为 \(t\)

首先字典序最小的最短路很好处理,记 \(pre_i\) 为源点到 \(i\) 的最短路中 \(i\) 前面的那个点,初始化 \(pre_i=i\),在松弛过程中加一个相等时的特判即可。

if(ds[v]>ds[u]+w){
  ds[v]=ds[u]+w;pre[v]=u;
  q.push(mkp(-ds[v],v));
}
else if(ds[v]==ds[u]+w)
  if(pre[v]>u)pre[v]=u;

查询路径就从 \(t\) 一直跳 \(pre\)

注意怪物的目标是与小 A 相遇,而小 A 行走的路线是确定的,那么怪物必然会先走到路线上的某一点再沿着路线追小 A,所以不妨枚举这个点。

以下怪物和小 A 的移动均用他们的起点来描述。

就枚举描蓝的这些点,设其为 \(i\),分类讨论:

  1. 如果 \(b\)\(i\) 了,\(s\) 还没到 \(i\),这时只有死路一条。追及问题,时间为 \(\Large\frac{ds_i+db_i}5\)

  2. \(b\) 到了 \(i\)\(s\) 也经过了 \(i\),这时就需要比较 \(s\)\(b\) 哪个先到达 \(t\),即 \(\Large\frac {ds_t}{2}\)\(\Large\frac {db_i+ds_t-ds_i}{3}\) 的大小,若前者大,那么会被抓住,时间化简后为 \(db_i-ds_i\)

  3. 若前者小,就能逃到 \(t\),这时怪物距 \(t\) 的距离化简后为 \(db_i-ds_i-\Large\frac {ds_t}{2}\)

到这里就写完了,剩下的就是一些细节问题。这里特别说一下输出的问题,使用 cout 输出会出现精度误差,如 \(5.243e6\) 等输出,直接使用 printf 保留小数又不能符合整数直接输出的要求。但题目中说答案不会超过两位小数,所以我们直接把边权 \(\times 100\) (这时路径长度要开 long long),这样保证运算时一直是整数,输出时是 \(100\) 的倍数就保留整数,是 \(10\) 的倍数保留一位小数,否则保留两位小数。

Code

#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define pb push_back
#define mkp make_pair
using namespace std;
using ll=long long;
using pii=pair<int,int>;
using pll=pair<ll,ll>;
using ull=unsigned long long;
inline void read(int &x){
  char ch=getchar();
  int r=0,w=1;
  while(!isdigit(ch))w=ch=='-'?-1:1,ch=getchar();
  while(isdigit(ch))r=(r<<1)+(r<<3)+(ch^48),ch=getchar();
  x=r*w;
}
const int N=2e5+7,inf=1e12+7;
vector<pii>edge[N];
int n,m,s,t,b,pre[N],path[N],cnt;
int db[N],ds[N];
bool bb[N];
priority_queue<pii>q;
void dij(int s){
  memset(ds,63,sizeof ds);memset(bb,0,sizeof bb);
  ds[s]=0;q.push(mkp(0,s));
  for(int i=1;i<=n;i++)pre[i]=i;
  while(!q.empty()){
    int u=q.top().se;q.pop();
    if(bb[u])continue;
    bb[u]=1;
    for(auto it:edge[u]){
      int v=it.fi,w=it.se;
      if(ds[v]>ds[u]+w){
        ds[v]=ds[u]+w;pre[v]=u;
        q.push(mkp(-ds[v],v));
      }
      else if(ds[v]==ds[u]+w)
        if(pre[v]>u)pre[v]=u;
    }
  }
}
void dij2(int s){
  memset(db,63,sizeof db);memset(bb,0,sizeof bb);
  db[s]=0;q.push(mkp(0,s));
  while(!q.empty()){
    int u=q.top().se;q.pop();
    if(bb[u])continue;
    bb[u]=1;
    for(auto it:edge[u]){
      int v=it.fi,w=it.se;
      if(db[v]>db[u]+w){db[v]=db[u]+w;q.push(mkp(-db[v],v));}
    }
  }
}
void write(int x){
  if(x%100==0)cout<<x/100;
  else if(x%10==0)printf("%.1lf",x/100.0);
  else printf("%.2lf",x/100.0);
}
main(){
  read(n);read(m);read(s);read(b);read(t);
  for(int i=1,x,y,z;i<=m;i++)
    read(x),read(y),read(z),edge[x].pb(mkp(y,z*100)),edge[y].pb(mkp(x,z*100));
  dij(s);
  int tmp=t;
  while(tmp!=s)path[++cnt]=tmp,tmp=pre[tmp];
  path[++cnt]=s;
  dij2(b);
  bool flag=1;
  int ans=inf,ans1=inf;
  for(int i=1;i<=cnt;i++){
    if(db[path[i]]/3.0<=ds[path[i]]/2.0)
      flag=0,ans=min(ans,(db[path[i]]+ds[path[i]])/5);
    else if((db[path[i]]+ds[t]-ds[path[i]])/3.0<=ds[t]/2.0)
      flag=0,ans=min(ans,db[path[i]]-ds[path[i]]);
    else if(flag)
      ans1=min(ans1,db[path[i]]-ds[path[i]]-ds[t]/2);
  }
  if(flag)puts("YES"),write(ans1);
  else puts("NO"),write(ans);
  return 0;
}
posted @ 2022-12-25 21:40  Epoch_L  阅读(27)  评论(0编辑  收藏  举报