您的位置:首页 > 编程语言 > Go语言

POJ 2263 Heavy Cargo (SPFA+Dijkstra,最短路变形)

2015-08-22 21:47 465 查看
题目链接: POJ 2263 Heavy Cargo

【题目大意】

某公司生产了一种巨型卡车,它的载重量并不在于它本身的载重量, 而只在于公路的载重量!

题目给你 开车运送的起点和终点 , 以及一些可供选择的道路, 每个道路标明了载重量。

让你求出从起点开到终点,卡车的最大载重量是多少 , 也就是起点到终点的通路中,载重量最小的道路的载重量。

【思路】

小技巧: 用map 实现字符串与数字的对应,注意要从1开始。

Dijkstra算法的变形 。

之前学图论的时候这个算法学的太快 没怎么练过,,以为用SPFA完全可以替代,,然而这两种算法的思想并不一样。

Dijkstra算法是从起点开始 ,每次在它相邻的节点中选出距离起点最近的那个点,更新时,将刚选出的节点临近的节点“显化”,也就是将minDist【】的值从INF 更新为当前到起点的距离, 缺点是要遍历n个节点 来找临近的点; 效率 O(n^2)

SPFA算法仅仅把比当前距离短的节点推入队列,再不断的从子节点中通过 松弛操作 找出当前的最短路。

本题是最短路的变形,, 每次寻找的是当前节点 附近节点的最大值而不是最短路,因为要让载重量尽可能的大,用Dijkstra的贪心思想很好想到,

int tmpmin = 0;
int addnode;
for(int i=1;i<=n;i++){
if(!inqueue[i]&&minDist[i]>tmpmin){ 找出临近节点最大的值
tmpmin = minDist[i];
addnode = i;
}
}


在节点更新的时候 minDist【】 并不是储存当前最短距离了,而是当前最小的载重量。

所以更新的时候 用临近节点的载重量 与 根节点(刚添加的节点)的载重量 比较选出最小的。

for(int i=0;i<G[addnode].size();i++){
          int vex = G[addnode][i].v;
          int value = G[addnode][i].len;
          if(!inqueue[vex]&&minDist[vex]<min(value,minDist[addnode])){
                minDist[vex]=min(value,minDist[addnode]);
          }
  }


【Dijkstra】

#include <iostream>
#include <cstdio>
#include <map>
#include <cstring>
#include <vector>
using namespace std;
const int maxn = 220;
struct node{
int v,len;
node(int v=0,int len=0):v(v),len(len){}
};
int minDist[maxn];
bool inqueue[maxn];
vector<node>G[maxn];
int  n,m;
void dijkstra(int st,int end){
memset(minDist,0,sizeof(minDist));
memset(inqueue,0,sizeof(inqueue));
minDist[st]=0;
inqueue[st]=true;
for(int i=0;i<G[st].size();i++){
int vex = G[st][i].v;
minDist[vex]=G[st][i].len;
}
for(int nodenum=1;nodenum<n;nodenum++){
int tmpmin = 0;
int addnode;
for(int i=1;i<=n;i++){
if(!inqueue[i]&&minDist[i]>tmpmin){
tmpmin = minDist[i];
addnode = i;
}
}
inqueue[addnode]=true;
for(int i=0;i<G[addnode].size();i++){
int vex = G[addnode][i].v;
int value = G[addnode][i].len;
if(!inqueue[vex]&&minDist[vex]<min(value,minDist[addnode])){
minDist[vex]=min(value,minDist[addnode]);
}
}
}
}
int main(){
map<string,int>mp; //
int cas=0;
while(scanf("%d%d",&n,&m)!=EOF&&(n||m)){
printf("Scenario #%d\n",++cas);
string a,b;
mp.clear();
for(int i=0;i<maxn;i++)
G[i].clear();
int len;
int cnt=0;
for(int i=0;i<m;i++){
cin>>a>>b>>len;
if(!mp[a]){ //用map 做string 与 int对应的时候,不要从0 开始 ,不好判断
mp[a]=++cnt; //从零开始 这个判断就错了
}
if(!mp[b])
mp[b]=++cnt;
G[mp[a]].push_back(node(mp[b],len));
G[mp[b]].push_back(node(mp[a],len));
}
cin>>a>>b;
dijkstra(mp[a],mp[b]);
cout<<minDist[mp[b]]<<" tons"<<endl<<endl;
}
return 0;
}


搞懂了上述传递状态的方法,SPFA的代码就很容易写出来了

【SPFA】

#include <iostream>
#include <cstdio>
#include <map>
#include <cstring>
#include <queue>
#include <vector>
#define INF 0xfffffff
using namespace std;
const int maxn = 220;
struct node{
int v,len;
node(int v=0,int len=0):v(v),len(len){}
};
int minDist[maxn];
bool inqueue[maxn];
vector<node>G[maxn];
int  n,m;
void SPFA(int st,int end){
memset(minDist,0,sizeof(minDist));
memset(inqueue,0,sizeof(inqueue));

inqueue[st]=true;
queue<int >Q;
minDist[st]=INF;
Q.push(st);
while(!Q.empty()){
int vex = Q.front();
Q.pop();
inqueue[vex]=0;
for(int i=0;i<G[vex].size();i++){
int v = G[vex][i].v;
int value = G[vex][i].len;
int tmp = max(minDist[v],min(minDist[vex],value));
if(tmp>minDist[v]){
minDist[v]=tmp;
if(!inqueue[v])
{
inqueue[v]=1;
Q.push(v);
}
}

}
}
}
int main(){
map<string,int>mp; //
int cas=0;
while(scanf("%d%d",&n,&m)!=EOF&&(n||m)){
printf("Scenario #%d\n",++cas);
string a,b;
mp.clear();
for(int i=0;i<maxn;i++)
G[i].clear();
int len;
int cnt=0;
for(int i=0;i<m;i++){
cin>>a>>b>>len;
if(!mp[a]){ //用map 做string 与 int对应的时候,不要从0 开始 ,不好判断
mp[a]=++cnt; //从零开始 这个判断就错了
}
if(!mp[b])
mp[b]=++cnt;
G[mp[a]].push_back(node(mp[b],len));
G[mp[b]].push_back(node(mp[a],len));
}
cin>>a>>b;
SPFA(mp[a],mp[b]);
cout<<minDist[mp[b]]<<" tons"<<endl<<endl;
}
return 0;
}


这一题在比赛的时候没有想出来怎么写,还是对算法原理掌握的不够清晰,光看模板是敲不出来新题的!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: