版权声明:如需转载请联系[email protected] https://blog.csdn.net/qq_20633793/article/details/82144193
思路:Dijkstra+DFS.如果只有Dijkstra是不可以的,因为minNeed和minBack在路径上的传递不满足最优子结构,不是简单的相加的过程,只有在所有路径都确定了之后才能区选择最小的need和最小的back
易错点:
返回过程中不调整,一个节点需要带来的数目和返回的数目没有关系,要分别将记录
不能只用Dijkstra
看清楚判断最有路径的条件,先选从0节点带走最少的,再选带到0节点最少的
#include<iostream>
#include<vector>
#include<set>
#include"string.h"
using namespace std;
#define _for(i,lo,hi) for(int i=(lo);i<(hi);i++)
int getint() {int x;scanf("%d",&x);return x;}
#define MAX 505
#define inf 0x7fffffff
struct node{int x,len;node(int xx,int ll):x(xx),len(ll){}};
vector<vector<node> > grid(MAX);//节点标号为1-N,从0出发
vector<vector<int> > path(MAX);
vector<int> vec,minpath;//记录中间路径,最短路径
int minwei=inf,minremain=inf;
int Cmax,N,Sp,M;//含义与题目同
vector<int> dist(MAX,inf),vis(MAX,false),weight(MAX);
void Dijkstra(){//x顶点到其他定点的单源最短路径
int id,len,n;
_for(k,0,N+1){
id=-1;len=inf;
//找到未发现的定点中的最近顶点,加入已发现集合
_for(i,0,N+1){
if(!vis[i]&&dist[i]<len){
len=dist[i];
id=i;
}
}
if(id==-1)return;
//从该定点更新状态数组
vis[id]=true;
n=grid[id].size();
int nextid;
_for(i,0,n){
nextid=grid[id][i].x;len=grid[id][i].len;//分别表示顶点和长度
if(!vis[nextid]){
if(dist[nextid]>dist[id]+len){
dist[nextid]=dist[id]+len;
path[nextid].clear();
path[nextid].push_back(id);
}else if(dist[nextid]==dist[id]+len){
path[nextid].push_back(id);
}
}
}
}
}
//遍历path向量,在最短路径中寻找
//这里每个节点需要两个标记,到达该节点需要带来的数目,从该节点需要带走的数目
//两者可能均不为0,比如前两个节点为-5,10,从0节点出发需要带5个,而从2节点返回时带10个,返回到0节点也要带上这10个
void DFS(int id,int wei,int remain){//Wei表示在id节点需要带来的数目,remain表示在id节点需要带走的数目
if(id==0){
if(wei<minwei){
minwei=wei;
minremain=remain;
minpath=vec;
}else if(wei==minwei&&remain<minremain){
minremain=remain;
minpath=vec;
}
return;
}
_for(i,0,path[id].size()){
int next=path[id][i];
vec.push_back(next);
if(weight[next]>=0){
if(weight[next]>=wei)
DFS(next,0,remain+weight[next]-wei);
else
DFS(next,wei-weight[next],remain);
}else{
DFS(next,wei-weight[next],remain);
}
vec.pop_back();
}
}
int main(){
//freopen("d:\\input.txt","r",stdin);
scanf("%d %d %d %d",&Cmax,&N,&Sp,&M);
_for(i,1,N+1){
weight[i]=getint()-Cmax/2;//输入时直接减去,后面可根据其正负判断
}
int c1,c2,len;
for(int i=1;i<=M;i++){
scanf("%d %d %d",&c1,&c2,&len);
grid[c1].push_back(node(c2,len));
grid[c2].push_back(node(c1,len));
}
//从0节点计算单源最短路径
dist[0]=0;
Dijkstra();
//测试中居然还存在Sp节点不是问题节点的情况,所以,初始化进入DFS要分此两种情况
if(weight[Sp]<0)
DFS(Sp,-weight[Sp],0);
else
DFS(Sp,0,weight[Sp]);
printf("%d ",minwei);
for(int i=minpath.size()-1;i>=0;i--){
printf("%d->",minpath[i]);
}
printf("%d ",Sp);
printf("%d\n",minremain);
return 0;
}