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\n",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

 

posted @ 2020-03-19 11:28  kongbursi  阅读(337)  评论(0编辑  收藏  举报