最短路径
题目来源:
最短路径
思路分析
- 由于是单源最短路径问题,所以采用Dijkstra算法
- 由于题目中距离很大,超出整数表示范围,所以自定义bigInteger,用于保存高精度整数。
代码
#include <stdio.h>
#include <vector>
using namespace std;
struct bigInteger{ //定义高精度整数,用于保存距离
int digit[1001];
int size;
void init(){
for(int i=0; i<1001; i++){
digit[i] = 0;
}
size = 0;
}
void set(int x){
init();
if(x==-1){ //当距离为-1表示两点之间没有直接通路
digit[0] = -1;
size = 1;
}
else{
do{
digit[size++] = x%10000;
x = x/10000;
}while(x!=0);
}
}
bigInteger operator * (int x) const{
int carry = 0;
bigInteger ret;
ret.init();
for(int i=0; i<size; i++){
ret.digit[ret.size++] = (digit[i]*x+carry)%10000;
carry = (digit[i]*x+carry)/10000;
}
if(carry!=0){
ret.digit[ret.size++] = carry;
}
return ret;
}
bigInteger operator + (const bigInteger A)const{
bigInteger ret;
ret.init();
int carry = 0;
for(int i=0; i<size||i<A.size; i++){
ret.digit[ret.size++] = (digit[i]+A.digit[i]+carry)%10000;
carry = (digit[i]+A.digit[i]+carry)/10000;
}
if(carry!=0){
ret.digit[ret.size++] = carry;
}
return ret;
}
int operator % (int x) const{
int remain = 0;
for(int i=size-1; i>=0; i--){
int temp = remain*10000+digit[i];
remain = temp%x;
}
return remain;
}
bool operator < (const bigInteger A) const{
if(size<A.size) return size<A.size;
else{
for(int i=size-1; i>=0; i--){
if(digit[i]!=A.digit[i])
return digit[i]<A.digit[i];
}
return digit[0]<A.digit[0];
}
}
}cost[501];
struct E{ //用于存储邻接链表的节点
int next; //与节点相邻的节点编号
bigInteger c; //与节点相邻的节点next和本节点之间的权值
};
vector<E> edge[501]; //邻接链表
bool mark[101]; //标记,当mark[j]为true时,表示结点j的最短路径长度已经得到,该结点已经加入集合k;
bigInteger dist[101]; //距离向量,当mark[i]为true时,表示已得的最短路径长度;否则,表示所有从开始结点出发,经过已知的最短路径达到集合k中的某结点,再经过一条边到达结点i的路径中最短的距离。
int main(int argc, const char * argv[]) {
int M,N;
while (scanf("%d%d", &N, &M)!=EOF){
for (int i=0; i<501; i++) {
edge[i].clear();
}
for (int i=0; i<101; i++) {
dist[i].init();
dist[i].set(-1);
mark[i] = false;
}
cost[0].set(1);
cost[1].set(2);
for(int i=0; i<M; i++){
int a,b;
scanf("%d%d", &a, &b);
if (i>1) {
cost[i] = cost[i-1]*2;
}
E temp;
temp.next = b;
temp.c = cost[i];
edge[a].push_back(temp);
temp.next = a;
edge[b].push_back(temp);
}
mark[0] = true;
int newP = 0; //集合中新加入的点为0;
dist[0].set(0);
for(int j = 1; j<N; j++){
for(int i=0; i<edge[newP].size(); i++){
int t = edge[newP][i].next; //与新加入的结点相邻的结点
bigInteger cc = edge[newP][i].c; //与新加入的结点相邻结点的权值
if (mark[t]==true) { //如果与新加入的结点相邻的结点已经在集合k,则跳过
continue;
}
bigInteger temp;
temp = dist[newP]+cc;
if(dist[t].digit[0]==-1||temp<dist[t]) //如果与新加入的结点相邻的结点之前不可达,或者通过新加入的结点到达的距离更短,则更新距离
dist[t] = temp;
}
bigInteger min;
min.size = 1001;
for (int i=0; i<1001; i++) { //最小值初始化为一个大整数,为找最小值做准备
min.digit[i] = 9999;
}
for (int i=1; i<=N; i++) { //遍历所有结点,找到还未放入集合k,且距离最小的结点设置为newP
if (mark[i]==true||dist[i].digit[0]==-1) {
continue;
}
if (dist[i]<min) {
min = dist[i];
newP = i;
}
}
mark[newP] = true; //把newP放入集合k
}
for (int i=1; i<N; i++) { //按照题目输出到所有结点的距离
printf("%d\n", dist[i]%100000);
}
}
return 0;
}