http://pat.zju.edu.cn/contests/pat-a-practise/1003
1、看清题意,求最短路径条数而非最短路径长度
2、相同最短路径,输出最大救援人数3、本题是结点附带一个权值(救援人数)与边上的权值不同,两种题型的相应处理熟练掌握
4、通过本题掌握:
1、dij求最短路径长度算法(邻接表)
2、求最短路径条数
3、带权值的最短路径求法①结点权值②边权值
#include <stdio.h>
#include <vector>
using namespace std;
struct E
{
int next;
int c;
};
vector<E> edge[505];
int dis[505]; //到i城市的最短距离
bool mark[505]; //是否访问过
int teamNum[505]; //最多500个城市,teamNum[i]--城市i的救援队伍人数
int num[505]; //保存最短路径下的最大救援人数,初始全为0
int count[505]; //保存到i点,多少条最短路径
void dij(int s,int e,int n)
{
int i,j;
dis[s]=0;
mark[s]=true;
num[s]=teamNum[s]; //赋初始值
count[s]=1; //从起点到起点,距离为0,当然最短路径条数为1
int newP=s;
for (i=0;i<n-1;i++) //dij算法共n-1次循环
{
for (j=0;j<edge[newP].size();j++) //遍历newP的邻接边,得到dis[j],num[j],count[j]
{
int t=edge[newP][j].next;
int c=edge[newP][j].c;
if (mark[t])
{
continue;
}
if (dis[t]==-1 || dis[t]>dis[newP]+c) //若有更短边,更新
{
dis[t]=dis[newP]+c;
num[t]=num[newP]+teamNum[t];
count[t]=count[newP]; //经过newP到t的条数也就等于到newP的条数
}
else if ( dis[t]==dis[newP]+c ) //距离相同,这才考虑路径数目增加
{
if (num[t]<num[newP]+teamNum[t]) //救援人数更多,更新
{
num[t]=num[newP]+teamNum[t];
} //newP与t直接相连,原先到t有count[t]条最短路径
count[t]+=count[newP]; // 由newP到t的条数也就等于到newP的条数
} //现在先到newP 有count[newP]条边,再到t,所以相加
int min=123123;
for (j=0;j<n;j++) //遍历所有点,找出当前最小边
{
if (mark[j])
{
continue;
}
if (dis[j]==-1)
{
continue;
}
if (dis[j]<min)
{
min=dis[j];
newP=j;
}
}
mark[newP]=true; //标记已访问
}
}
int main()
{
int n,m,i,s,e; //n个城市,m条路,起点s,终点e
E tmp;
scanf("%d%d%d%d",&n,&m,&s,&e);
for (i=0;i<n;i++) //输入n个城市相应救援队伍人数
{
scanf("%d",&teamNum[i]);
}
for (i=0;i<n;i++) //初始化清空邻接表
{
edge[i].clear();
}
while (m--) //m条道路信息
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
tmp.c=c;
tmp.next=a;
edge[b].push_back(tmp); //无向图,边插入邻接表
tmp.next=b;
edge[a].push_back(tmp);
}
for (i=0;i<n;i++) //初始化清空 距离数组,标记数组
{
dis[i]=-1;
mark[i]=false;
}
dij(s,e,n); //求从s到e的最短距离
printf("%d %d\n",count[e],num[e]);
return 0;
}