• nuoyanli 520 Let‘s play computer game


    H

    描述

    xxxxxxxxx在疫情期间迷上了一款游戏,这个游戏一共有nnn个地点(编号为1——n1——n1——n),他每次从一个地点移动到另外一个地点需要消耗

    一定的能量,每一个地点都有一些珠宝,输入中会把每一个地方的珠宝价值估算成一个值。

    xxxxxxxxx想请聪明的你帮他找出来从编号为sss的地点,到编号为ddd的地点最小要消耗多少能量,消耗这些能量最多获得多少价值的珠宝

    输入

    第一行输入n,s,dn,s,dn,s,d。其意义如上描述 (n&lt;520n&lt;520n<520)

    第二行有nnn个数XiX_iXi​,比如i==1i==1i==1描述编号为1的点有珠宝价值为XiX_iXi​(这里保证XiX_iXi​大于等于0) (Xi&lt;1000X_i&lt;1000Xi​<1000)

    下面输入一个n∗nn*nn∗n的矩阵,比如第iii行,第j列的值为xxx,就表示从编号为iii到编号为jjj的地方距离为x (x&lt;1000)x  (x&lt;1000)x (x<1000)

     

    注意:这是一个单向路,即从编号为iii到编号为jjj的距离可能不等于从编号为jjj到编号为iii

    输出

    输出占一行,第一个数是最小要消耗多少能量,第二个数是消耗这些能量最多获得多少价值的珠宝。两个数用空格分开

    输入样例 1

    4 1 4

    20 30 40 10

    0 1 2 3

    999 0 999 2

    999 999 0 2

    999 999 999 0

    输出样例 1

    3 60

    输入样例 2

    7 2 3

    341 527 189 740 490 388 989

    0 489 711 174 305 844 971

    492 0 998 954 832 442 424

    619 906 0 154 293 395 439

    735 738 915 0 453 748 786

    550 871 932 693 0 326 53

    904 732 835 354 364 0 691

    669 157 719 282 875 573 0

    输出样例 2

    998 716

    提示

    第一个样例解释:

    解释:

    把这个矩阵翻译成边

    1->2 1

    2->4 2

    1->4 3

    1->3 2

    3->4 2

    正确路径:1->2->4

     

     

     

    题目正解:最短路+dfs 或 最短路+dp。

    题目灵感:L2-001 紧急救援 (25分)。

    题目大意描述:

    让你找出来最短路径,如果最短路径有多条,那就取出来每一条路径中 所有点权值之和 最大的那个路径(点权值是什么意思?就是题目中说的每一个点的珠宝价值)

    题目解法1:最短路+dfs

    按照题目描述我们就需要先找出来最短路的大小,然后我们知道这个大小之后就dfs去跑图,找到每一条能从起点s到终点d的路径,然后每一条路径肯定有一个路径长度,我们只保留那个与最短路大小相等的长度的路径

    然后对每一条路径在dfs过程中记录它所经过每一个点,把这些点的权值加到一起,我们设这个值为总值

    那么每一条路径都有一个总值,我们只需要从中找出来最大的那个输出就行

    Dfs代码如下:

    void dfs(int x,int value)
    {
        if(x==d)
        {
            if(result<value)
            {
                result=value;
            }
            return;
        }
        for(int i=1; i<=n; ++i)
        {
            if(!vis[i] && dist[i]==dist[x]+G[x][i] && G[x][i])
            {
                vis[i]=1;
                dfs(i,value+val[i]);
                vis[i]=0;
            }
        }
    }

    这里我们为了避免盲目的搜索所有路径,我们可以加一个限制条件来优化dfs:

    dist[i]==dist[x]+G[x][i]   //dist是我们跑最短路之后跑出来的单源最短路数组

    假设一条路径例如s->2->3->d,如果你dfs过程中s->2->3的长度不等于dist[3] ,那么就算dfs到终点d这条路径长度绝对不可能等于dist[d]

    至于为什么这里就不多说了,自己想一下

    代码:

      1 #include<stdio.h>
      2 #include<string.h>
      3 #include<iostream>
      4 #include<algorithm>
      5 #include<queue>
      6 #include<vector>
      7 using namespace std;
      8 typedef long long ll;
      9 const int inf = 0x3f3f3f3f;
     10 const int maxn = 550;
     11 int n,m,s,d;
     12 int val[maxn],vis[maxn],dist[maxn];
     13 int G[maxn][maxn],result;
     14 int int_rand(int min,int max)
     15 {
     16     return int(min+rand()%(max-min));
     17 }
     18 struct shudui1
     19 {
     20     int start,value;
     21     bool operator < (const shudui1 q)const
     22     {
     23         return value<q.value;
     24     }
     25 } str1;
     26 priority_queue<shudui1>r;
     27 void dijkstra()
     28 {
     29     memset(vis,0,sizeof(vis));
     30     memset(dist,inf,sizeof(dist));
     31     dist[s]=0;
     32     str1.start=s;
     33     str1.value=0;
     34     r.push(str1);
     35     while(!r.empty())
     36     {
     37         int x,y;
     38         str1=r.top();
     39         r.pop();
     40         x=str1.start;
     41         y=str1.value;
     42         if(dist[x]<y) continue;
     43         for(int i=1; i<=n; ++i)
     44         {
     45             if((dist[x]+G[x][i]<dist[i]))
     46             {
     47                 dist[i]=dist[x]+G[x][i];
     48                 str1.start=i;
     49                 str1.value=dist[i];
     50                 r.push(str1);
     51             }
     52         }
     53     }
     54 }
     55 void dfs(int x,int value)
     56 {
     57     if(x==d)
     58     {
     59 
     60         if(result<value)
     61         {
     62             result=value;
     63         }
     64         return;
     65     }
     66     for(int i=1; i<=n; ++i)
     67     {
     68         if(!vis[i] && dist[i]==dist[x]+G[x][i] && G[x][i])
     69         {
     70             vis[i]=1;
     71 
     72             dfs(i,value+val[i]);
     73 
     74             vis[i]=0;
     75         }
     76     }
     77 }
     78 int main()
     79 {
     80     int u,v,w;
     81     scanf("%d%d%d", &n, &s, &d);
     82     for(int i = 1; i <= n; i ++)
     83     {
     84         scanf("%d", &val[i]);
     85     }
     86     for(int i = 1; i <= n; i ++)
     87     {
     88         for(int j = 1; j <= n; j ++)
     89         {
     90             scanf("%d",&G[i][j]);
     91         }
     92     }
     93     dijkstra();
     94     result=0;
     95     memset(vis,0,sizeof(vis));
     96     vis[s]=1;
     97     dfs(s,val[s]);
     98     printf("%d %d
    ",dist[d],result);
     99     return 0;
    100 }
    View Code

    题目解法2:最短路+dp

    题外话:这个方法其实我并没有想到,还是yzj验题之后给me说的(牛掰)

     

    for(ll i=0; i<len; i++)
            {
                ll v=vec[t][i].v;
                ll w=vec[t][i].w;
                if(dis[t]+w<dis[v])
                {
                    dp[v]=dp[t]+sc[v]; //当s->v的最短路径已然变得更小,那么dp值要重新赋值,而不是比较之后再赋值
                    dis[v]=dis[t]+w;
                    if(!vis[v])
                    {
                        vis[v]=1;
                        q.push(v);
                    }
                }
                else if(dis[t]+w==dis[v]) //相对于原版spay算法,这里多了一个判断。多这个判断的意义和上面第一种解法的dfs里面多一个判断那个差不多
                {
                    if(dp[v]<dp[t]+sc[v])//这里要想给dp[v]赋值就要通过判断,因为我们要输出总值最大的那个路径
                    {
                        dp[v]=dp[t]+sc[v];
                        if(!vis[v])
                        {
                            vis[v]=1;
                            q.push(v);//如果这个点满足条件,那么我们还要把这个点放入队列,那么相比于原spay算法这个代码复杂度就要大一点,但是还是要比第一种方法复杂度低
                        }
                    }
                }
            }

    Dp关键部分就是上面代码,也就是在spay算法的while循环里面

    解释一下每一个数组:

    Dis数组是存放单源最短路结果

    Vis数组是用来标记某一个点是否进入队列中(等于1就代表在队列)

    Dp[i]数组初值是等于i点的权值(点权值是什么意思?就是题目中说的每一个点的珠宝价值),这个数组的作用就是找出来题目第二个输出结果

    Sc[]数组初值是等于i点的权值

     代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 const ll maxn=2e3+5;
     5 ll sc[maxn],dis[maxn],vis[maxn],ans;
     6 ll dp[maxn],pre[maxn];
     7 struct node
     8 {
     9     ll v,w;
    10 } p;
    11 vector<node>vec[maxn];
    12 vector<ll>ve[maxn];
    13 queue<ll>q;
    14 void spfa(ll u)
    15 {
    16     memset(dis,0x3f3f3f3f,sizeof(dis));
    17     memset(vis,0,sizeof(vis));
    18     dis[u]=0;
    19     q.push(u);
    20     while(!q.empty())
    21     {
    22         ll t=q.front();
    23         vis[t]=0;
    24         q.pop();
    25         ll len=vec[t].size();
    26         for(ll i=0; i<len; i++)
    27         {
    28             ll v=vec[t][i].v;
    29             ll w=vec[t][i].w;
    30             if(dis[t]+w<dis[v])
    31             {
    32                 dp[v]=dp[t]+sc[v];
    33                 dis[v]=dis[t]+w;
    34                 if(!vis[v])
    35                 {
    36                     vis[v]=1;
    37                     q.push(v);
    38                 }
    39             }
    40             else if(dis[t]+w==dis[v])
    41             {
    42                 if(dp[v]<dp[t]+sc[v])
    43                 {
    44                     dp[v]=dp[t]+sc[v];
    45                     if(!vis[v])
    46                     {
    47                         vis[v]=1;
    48                         q.push(v);
    49                     }
    50                 }
    51             }
    52         }
    53     }
    54 }
    55 int main()
    56 {
    57     ios::sync_with_stdio(false);
    58     cin.tie(0);
    59     ll n,s,d;
    60     cin>>n>>s>>d;
    61     for(ll i=1; i<=n; i++)
    62         cin>>sc[i],dp[i]=sc[i];
    63     ll w;
    64     for(ll i=1; i<=n; i++)
    65         for(ll j=1; j<=n; j++)
    66         {
    67             if(i==j)
    68                 cin>>w;
    69             else
    70                 cin>>w,p.v=j,p.w=w,vec[i].push_back(p);
    71         }
    72     spfa(s);
    73     cout<<dis[d]<<' '<<dp[d]<<endl;
    74 }
    View Code
  • 相关阅读:
    PHP Cookbook读书笔记 – 第18章安全和加密
    ANDROID开发之http调试常见错误
    GD库之有意思的imagesetstyle
    PHP Cookbook读书笔记 – 第06章函数
    PHP Cookbook读书笔记 – 第09章表单
    PHP Cookbook读书笔记 – 第04章数组
    PHP Cookbook读书笔记 – 第17章图形
    PHP常见面试问题
    SQL SERVER 表分区实施步奏
    PHP Cookbook读书笔记 – 第12章XML
  • 原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/12522941.html
Copyright © 2020-2023  润新知