Input
Each input file contains one test case. For each test case, the first line contains 4 positive integers: N (<= 500) - the number of cities (and the cities are numbered from 0 to N-1), M - the number of roads, C1 and C2 - the cities that you are currently in and that you must save, respectively. The next line contains N integers, where the i-th integer is the number of rescue teams in the i-th city. Then M lines follow, each describes a road with three integers c1, c2 and L, which are the pair of cities connected by a road and the length of that road, respectively. It is guaranteed that there exists at least one path from C1 to C2.
Output
For each test case, print in one line two numbers: the number of different shortest paths between C1 and C2, and the maximum amount of rescue teams you can possibly gather.
All the numbers in a line must be separated by exactly one space, and there is no extra space allowed at the end of a line.
Sample Input
5 6 0 2 1 2 1 5 3 0 1 1 0 2 2 0 3 1 1 2 1 2 4 1 3 4 1
Sample Output
2 4
#include <stdio.h>
#include <vector>
using namespace std;
const int maxint=-1; //-1表示当前路径不存在或当前节点路径信息未被初始化
int N,M,c1,c2;
vector<int> hands; //每个城市救援人员
vector<bool> fl;
vector< vector<int> > roads; //保存路径信息
void dfs(int s,int end); //深搜函数
int mincost(maxint),maxhand,pathn; //对应最短用时,最多救援人员,最短路径数
int time,hand; //到达当前点的路径时间,救援人员
int main()
{
scanf("%d %d %d %d",&N,&M,&c1,&c2);
hands.resize(N);
fl.resize(N,false);
fl[c1]=true;
for(int i=0;i<N;i++) scanf("%d",&hands[i]);
roads.resize(N,vector<int> (N,maxint));
for(int i=0;i<M;i++)
{
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
roads[a][b]=c;
roads[b][a]=c;
}
hand=hands[c1]; //千万要记得初始化,因为c2=c1的情况下判断会被跳过,测试点2通不过有可能是这个原因
time=0;
maxhand=hands[c1];
pathn=1;
dfs(c1,c2);
printf("%d %d",pathn,maxhand);
return 0;
}
void dfs(int s,int e)
{
for(int i=0;i<N;i++)
{
if(roads[s][i]!=maxint&&!fl[i]) //注意:c2=c1的情况下,判断会被跳过
{
if(time>mincost&&mincost!=maxint) break; //时间已超过mincost
time+=roads[s][i];
hand+=hands[i];
fl[i]=true;
if(i==e) //到终点时对路径信息进行判断
{
if(time<mincost||mincost==maxint)
{
mincost=time;
maxhand=hand;
pathn=1;
}
else
{
if(time==mincost)
{
pathn++;
if(maxhand<hand) maxhand=hand;
}
}
}
else dfs(i,e);
time-=roads[s][i]; //释放该路径的信息
hand-=hands[i];
fl[i]=false;
}
}
}
dijkstra回溯解法:
首先由dj算法求出最短路径的所有可能取值,之后通过回溯计算考虑筛选路径的条件,给出最适合的一条路径,得到题目中要求的输出信息。在输出信息中要求输出path时可以将每次比较最符合筛选条件的前置点加入path,然后递归。
#include <stdio.h>
#include <vector>
using namespace std;
const int maxint=-1;
int N,M,c1,c2;
vector<int> hands;
vector< vector<int> > roads;
vector< vector<int> > pre;
void dijkstra(int s,int e);
int dfs(int e);
int pathn;
int main()
{
scanf("%d %d %d %d",&N,&M,&c1,&c2);
pre.resize(N);
hands.resize(N);
for(int i=0;i<N;i++) scanf("%d",&hands[i]);
roads.resize(N,vector<int> (N,maxint));
for(int i=0;i<M;i++)
{
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
roads[a][b]=c;
roads[b][a]=c;
}
dijkstra(c1,c2);
int hand;
hand=dfs(c2);
printf("%d %d",pathn,hand);
return 0;
}
void dijkstra(int s,int e)
{
vector<int> dist(N,maxint);
vector<bool> fl(N,false);
fl[s]=true;
dist[s]=0;
pre[s].push_back(-1);
int u=s;
while(!fl[e])
{
for(int i=0;i<N;i++)
{
if(!fl[i]&&roads[u][i]!=maxint)
{
int newdist=roads[u][i]+dist[u];
if(dist[i]==maxint||dist[i]>newdist)
{
dist[i]=newdist;
if(!pre.empty()) pre[i].clear();
pre[i].push_back(u);
}
else{ if(dist[i]==newdist) pre[i].push_back(u); }
}
}
int tmp=maxint;
for(int i=0;i<N;i++)
{
if(!fl[i]&&dist[i]!=maxint)
{
if(dist[i]<tmp||tmp==maxint)
{
tmp=dist[i];
u=i;
}
}
}
fl[u]=true;
}
}
int dfs(int e)
{
int u=e;
int mhand(0);
if(pre[u][0]==-1)
{
pathn++; //每次回溯至起点,路径值+1
return hands[u];
}
for(int i=0;i<pre[u].size();i++)
{
int hand=hands[u]+dfs(pre[u][i]);
if(hand>mhand) mhand=hand; //找出人数最多的一条路径,如果要得出路径,可以在这里将前置点push_back
}
return mhand;
}
dijkstra解法:
此解法首先需要的是创建一个存储有用节点信息的结构,必不可少的结构是bool fl作为该点路径是否确定的标志位以及int cost 最短时间。根据题设还需要添加的是int hand 救援人数, int pathn 最短路径数。解题思路是每次dj更新最少耗时的同时更新未确定节点的相关信息,当到达目标点时,需要输出的信息已经更新为最符合题设的形式,由于减少了回溯的过程,运行用时有所提高。在输出结果要求输出path时,可以将符合规定的前置节点索引加入节点结构中。
#include <stdio.h>
#include <vector>
using namespace std;
const int maxint=-1;
int N,M,c1,c2;
vector<int> hands;
vector< vector<int> > roads;
struct node
{
bool fl;
int cost; //最少耗时
int hand; //救援人员
int pathn; //路径数
};
vector<node> cn;
void dijkstra(int s,int e);
int main()
{
scanf("%d %d %d %d",&N,&M,&c1,&c2);
hands.resize(N);
for(int i=0;i<N;i++) scanf("%d",&hands[i]);
roads.resize(N,vector<int> (N,maxint));
for(int i=0;i<M;i++)
{
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
roads[a][b]=c;
roads[b][a]=c;
}
node nodei;
nodei.cost=maxint;
nodei.fl=false;
nodei.hand=0;
nodei.pathn=0;
cn.resize(N,nodei);
dijkstra(c1,c2);
printf("%d %d",cn[c2].pathn,cn[c2].hand);
return 0;
}
void dijkstra(int s,int e)
{
cn[s].fl=true;
cn[s].cost=0;
cn[s].hand=hands[c1];
cn[s].pathn=1;
int u=s;
while(!cn[e].fl)
{
for(int i=0;i<N;i++)
{
if(!cn[i].fl&&roads[u][i]!=maxint)
{
int newdist=roads[u][i]+cn[u].cost;
if(newdist<cn[i].cost||cn[i].cost==maxint) //求当前最短路径
{
cn[i].cost=newdist;
cn[i].pathn=cn[u].pathn;
cn[i].hand=cn[u].hand+hands[i];
}
else
{
if(newdist==cn[i].cost) //路径相等时比较救援人数,最后一个测试点通不过的原因
{
cn[i].pathn+=cn[u].pathn;
int newhand=cn[u].hand+hands[i];
if(newhand>cn[i].hand) cn[i].hand=newhand;
}
}
}
}
int tmp(maxint);
for(int i=0;i<N;i++)
{
if(!cn[i].fl&&cn[i].cost!=maxint)
{
if(tmp==maxint||tmp>cn[i].cost)
{
tmp=cn[i].cost;
u=i;
}
}
}
cn[u].fl=true;
}
}