题目描述
有n个点,m条无向边,有A,B两个人,初始时刻A在点1,B在点2,他们要走到点n去。A每走一条边,要消耗B单位能量,B每走一条边,要消耗E单位能量。如果A,B相伴走,则只消耗P单位的能量。请问A,B走到点n,最少要消耗多少能量?
输入数据保证1和n,2和n连通。
输入
第一行包含整数B,E,P,N和M,所有的整数都不超过40000,N>=3.
接下来M行,每行两个整数,表示该无向边连接的两个顶点。
输出
一个整数,表示最小要消耗的能量。
样例输入
4 4 5 8 8 1 4 2 3 3 4 4 7 2 5 5 6 6 8 7 8
样例输出
22
解题思路
看起来还挺复杂的,令人想打暴搜,不过,此题倒真是跟搜索有关,需要利用图的遍历。我们要求的路程其实就可以看成是两人走到一个点,然后再一起走到n点所用的最小花费,由于每走一步花费固定,我们就可以用3个dis数组来储存三个点(1,2,n)到i点的最小步数,这样处理,我们不用通过什么SPFA那些的图论算法,用深搜就可以解决了。最后再枚举1到n,求出这三个路程的最小值即可。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<cstdlib>
#define N 40005
using namespace std;
/*struct edge(){
int u,v;
edge(){};
edge(int U,int V){
u = U;
v = V;
}
};*/
int b,e,p,n,m , dis1[N], dis2[N],dis3[N],vis[N] , ans = N*N;
int que[N],head,tail;
vector<int>G[N];
void bfs(int step,int dis[]){
memset(vis,0,sizeof(vis));
dis[step] = 0;
vis[step] = 1;
head = tail = 1;
que[head] = step;
while (head <= tail){
int t = que[head];
int len = G[t].size();
for (int i = 0; i < len ; i ++ ){
if (!vis[G[t][i]]){
que[++ tail] = G[t][i];
vis[G[t][i]] = 1;
dis[G[t][i]] = dis[t] + 1;
}
}
head ++ ;
}
}
int main(){
scanf("%d%d%d%d%d",&b,&e,&p,&n,&m);
for (int i = 1;i <= m ;i ++ ){
int a,b;
scanf("%d%d",&a,&b);
G[a].push_back(b);
G[b].push_back(a);
}
bfs(1,dis1);
bfs(2,dis2);
bfs(n,dis3);
for (int i = 1 ;i <= n;i ++ ){
ans = min(ans , dis1[i] * b + dis2[i] * e + dis3[i] * p);
}
printf("%d",ans);
}
总结
这样看起来这道题挺水啊,事实上是这样的,基本没考到什么高级算法,关键看你是否找到了题目中这样的性质或者说是这样做的思路。事实证明一些图论题目可以说并没有这么难吧。考试的时候可以说是没怎么看这道题,看了一下,发现是有关图论的,当场就有点怕,又一直在想这是怎样的算法才可以通过,都没有仔细算过。当时还想了一些特殊的点,但对于正确算法都没有太大的实际意义。于是,我发现题目当中的一些特殊性质还是要能够抓住,这样才能令做题如有神助。(实话说,第一道题耗费了我大量时间,导致全盘爆炸,可以说是模拟考试中考得最差的一次,不过事实证明,这道题如果我打了样例,我将上升近10名。。。。)