zoukankan      html  css  js  c++  java
  • [测试题]香港记者

    Description

    众所周知,香港记者跑得比谁都快,这其中其实是有秘诀的。
    首先他们会跑最短路,但是最短路会有很多条,而且其他记者也知道要跑最短路,香港记者还统计出了每座城市带黑框眼镜的人数,如果一个记者跑路的时候城市带黑框眼镜人数的序列字典序比另一个记者大,那么这个记者就会被不可描述的力量续走时间,导致他跑得没字典序小的记者快。
    长者日续万秒日理万机,想请你告诉他香港记者经过的总路程和城市带黑框眼镜人数的序列,方便他找到香港记者,传授他们一些人生经验。
    方便起见,设起点为 1 终点为 n
    由于续命的多样性不可描述的力量,各个城市带黑框眼镜的人数各不相同。

    Input

    输入文件名为 journalist.in
    第一行,两个整数 n; m 表示有 n 个城市,城市之间有 m 条有向边。
    第二行, n 个数,表示每个城市带黑框眼镜的人数 bi
    接下来 m 行,每行 3 个非负整数 ui; vi; wi
    表示一条有向边的起点,终点,路程。

    Output

    输出文件名为 journalist.out
    第一行,一个非负整数表示香港记者经过的总路程。
    第二行,若干个非负整数表示香港记者经过的城市带黑框眼镜人数的序列

    Sample Input

    8 9
    1 2 3 4 5 6 7 8
    1 2 2
    2 3 3
    3 8 3
    1 4 3
    4 5 2
    5 8 1
    1 6 1
    6 7 2
    7 8 3

    Sample Output

    6
    1 4 5 8

    Hint

    对于前 30% 的数据, 2 n 2 × 1031 m 4 × 103
    对于前 60% 的数据,保证数据随机。
    对于另外 30% 的数据,保证所有起点到终点的简单路径(没有环的路径)长度相同。
    对于 100% 的数据, 2 n 2 × 1051 m 4 × 1051 w 1 × 109,存在至少一条从
    起点到终点的最短路。

    题解

    解法一:

    我们可以先求出最短路。

    然后搜索求出路径。

    对于$u->v$,如果

    $$dist[v]==dist[u]+w(u,v)$$

    就继续拓展。

    我们可以加边的时候先将后继节点按点权排序,这样贪心保证搜出的第一条策略就是满足条件的。

      1 #include<set>
      2 #include<map>
      3 #include<cmath>
      4 #include<ctime>
      5 #include<queue>
      6 #include<stack>
      7 #include<vector>
      8 #include<cstdio>
      9 #include<string>
     10 #include<cstdlib>
     11 #include<cstring>
     12 #include<iostream>
     13 #include<algorithm>
     14 #define LL long long
     15 #define RE register
     16 #define IL inline
     17 using namespace std;
     18 const int N=2e5;
     19 const int M=4e5;
     20 
     21 IL int Read()
     22 {
     23     int sum=0;
     24     char c=getchar();
     25     while (c<'0'||c>'9') c=getchar();
     26     while (c>='0'&&c<='9') sum=sum*10+c-'0',c=getchar();
     27     return sum;
     28 }
     29 
     30 int n,m,u,v,w;
     31 int b[N+5];
     32 struct ss
     33 {
     34     int u,v,w;
     35 }lin[M+5];
     36 bool comp(const ss &x,const ss &y) {return x.u==y.u ? b[x.v]>b[y.v]:x.u<y.u;}
     37 struct tt
     38 {
     39     int to,next,cost;
     40 }edge[M+5];
     41 int path[N+5],top;
     42 IL void Add(int u,int v,int w);
     43 
     44 LL dist[N+5];
     45 IL void SPFA();
     46 
     47 int keep[N+5],tot;
     48 void put_road(int r);
     49 
     50 int main()
     51 {
     52     n=Read(),m=Read();
     53     for (RE int i=1;i<=n;i++) b[i]=Read();
     54     for (RE int i=1;i<=m;i++) lin[i].u=Read(),lin[i].v=Read(),lin[i].w=Read();
     55     sort(lin+1,lin+1+n,comp);
     56     for (RE int i=1;i<=m;i++) Add(lin[i].u,lin[i].v,lin[i].w);
     57     SPFA();
     58     printf("%lld
    ",dist[n]);
     59     keep[++tot]=b[1];
     60     put_road(1);
     61     return 0;
     62 }
     63 
     64 IL void Add(int u,int v,int w)
     65 {
     66     edge[++top].to=v;
     67     edge[top].next=path[u];
     68     edge[top].cost=w;
     69     path[u]=top;
     70 }
     71 IL void SPFA()
     72 {
     73     memset(dist,127/3,sizeof(dist));
     74     dist[1]=0;
     75     bool vis[N+5]={0};
     76     vis[1]=1;
     77     queue<int>Q;
     78     while (!Q.empty()) Q.pop();
     79     Q.push(1);
     80     while (!Q.empty())
     81     {
     82         int u=Q.front(),v;Q.pop();vis[u]=0;
     83         for (RE int i=path[u];i;i=edge[i].next)
     84         {
     85             v=edge[i].to;
     86             if (dist[v]>dist[u]+edge[i].cost)
     87             {
     88                 dist[v]=dist[u]+edge[i].cost;
     89                 if (!vis[v])
     90                 {
     91                     vis[v]=1;
     92                     Q.push(v);
     93                 }
     94             }
     95         }
     96     }
     97     return;
     98 }
     99 
    100 void put_road(int r)
    101 {
    102     if (r==n)
    103     {
    104         for (RE int i=1;i<=tot;i++) printf("%d ",keep[i]);
    105         exit(0);
    106     }
    107     for (int i=path[r];i;i=edge[i].next) if (dist[edge[i].to]==dist[r]+edge[i].cost)
    108     {
    109         keep[++tot]=b[edge[i].to];
    110         put_road(edge[i].to);
    111         tot--;
    112     }
    113 }
    解法一

    解法二:

    我们可以存储逆边,逆向做一次$SPFA$。

    $pre[u]$表示$u$的后继节点

    松弛的时候如果

    $$dist[v]>dist[u]+w(u,v)$$

    $$dist[v]=dist[u]+w(u,v);$$

    如果

    $$dist[v]==dist[u]+w(u,v)$$

    此时若$pre[v]$的点权大于$u$的点权,我们将

    $$pre[v]=u;$$

    由于字典序高位越小越好,满足最优子结构,贪心是可行的。

     1 #include<set>
     2 #include<map>
     3 #include<cmath>
     4 #include<ctime>
     5 #include<queue>
     6 #include<stack>
     7 #include<vector>
     8 #include<cstdio>
     9 #include<string>
    10 #include<cstdlib>
    11 #include<cstring>
    12 #include<iostream>
    13 #include<algorithm>
    14 #define LL long long
    15 #define RE register
    16 #define IL inline
    17 using namespace std;
    18 const int N=2e6;
    19 const int INF=~0u>>1;
    20 
    21 IL int Read()
    22 {
    23     int sum=0;
    24     char c=getchar();
    25     while (c<'0'||c>'9') c=getchar();
    26     while (c>='0'&&c<='9') sum=sum*10+c-'0',c=getchar();
    27     return sum;
    28 }
    29 IL void put(int d)
    30 {
    31     if (!d) return;
    32     put(d/10);
    33     putchar(d%10+'0');
    34 }
    35 
    36 IL int Min(const int &a,const int &b) {return a<b ? a:b;}
    37 IL int Max(const int &a,const int &b) {return a>b ? a:b;}
    38 
    39 int t,n,k,f,maxn;
    40 int a[N+5];
    41 int s[N+5];
    42 
    43 int main()
    44 {
    45     t=Read();
    46     while (t--)
    47     {
    48         n=Read();k=Read();f=Read();
    49         maxn=0;
    50         memset(s,0,sizeof(s));
    51         for (RE int i=1;i<=n;i++) a[i]=Read(),maxn=Max(maxn,a[i]),s[a[i]]++;
    52         for (RE int i=1;i<=maxn;i++) s[i]+=s[i-1];
    53         for(RE int d=1;d<=maxn;d++)
    54             {
    55                 int cnt=s[d-1];
    56                 for(RE int j=d;cnt<=f&&j+k+1<=maxn;j+=d)
    57                     if (j+k<Min(maxn,j+d-1)) cnt+=s[Min(maxn,j+d-1)]-s[j+k];
    58                 if (cnt<=f) put(d),putchar(' ');
    59             }
    60         putchar('
    ');
    61     }
    62     return 0;
    63 }
    解法二
  • 相关阅读:
    面试题:垂直居中几种方法
    零碎记忆--随机
    v-model 和 :model 的区别
    Vue--keep-alive 理解
    vue 中 $route 和 $router 的区别
    Vue + Element UI 实现权限管理系统 前端篇(十):动态加载菜单
    Vue + Element UI 实现权限管理系统 前端篇(九):接口格式定义
    Vue + Element UI 实现权限管理系统 前端篇(八):管理应用状态
    Vue + Element UI 实现权限管理系统 前端篇(七):功能组件封装
    [2020牛客暑期多校训练营(第十场)C Decrement on the Tree]
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/7405305.html
Copyright © 2011-2022 走看看