九度OJ-1100:最短路径

  本题是做过的第一题五星题,综合性较大——Dijkstra+高精度整数。

  (在做本题的过程中突然开窍把高精度整数的int2BigInt与char2BigInt函数的功能用对=重载来代替了哈哈)

题目描述:

N个城市,标号从0到N-1,M条道路,第K条道路(K从0开始)的长度为2^K,求编号为0的城市到其他城市的最短距离

输入:

第一行两个正整数N(2<=N<=100)M(M<=500),表示有N个城市,M条道路
接下来M行两个整数,表示相连的两个城市的编号

输出:

N-1行,表示0号城市到其他城市的最短路,如果无法到达,输出-1,数值太大的以MOD 100000 的结果输出。

样例输入:
4 4
1 2
2 3
1 3
0 1
样例输出:
8
9
11
来源:
2010年上海交通大学计算机研究生机试真题
答疑:
解题遇到问题?分享解题心得?讨论本题请访问: http://t.jobdu.com/thread-7823-1-1.html



#include <iostream>
#include <vector>
#include <cstring>
#include <stack>
#include <iomanip>
#define MAXSIZE 100 
using namespace std;

struct BigInt{
	int digit[MAXSIZE];
	int intSize;
	void initBigInt(){
		for (int i=0;i<MAXSIZE;i++)
			digit[i]=0;
		intSize=0;
	} 
	void int2BigInt(int x){//the basic function    //初值不为0,而是NULL(intSize=0)
		initBigInt();
		do{//注意这里与n进制化成十进制一样,也要考虑x=0的情况 ********
			digit[intSize]=x%10000;
			intSize++;
			x/=10000;
		}while (x>0);
	}
	void char2BigInt(char *s){
		initBigInt();
		int weight;
		for (int i=strlen(s)-1;i>=0;i-=4){
			weight=1;
			for (int j=i;j>i-4&&j>=0;j--){
				digit[intSize]+=(s[j]-'0')*weight;
				weight*=10;
			}
			intSize++;
		}
	}
	BigInt operator+(const BigInt &a)const{
		BigInt sum;
		sum.initBigInt();
		int c=0;
		int i;
		for (i=0;i<intSize||i<a.intSize;i++){
			sum.digit[i]=c+digit[i]+a.digit[i];
			c=sum.digit[i]/10000;
			sum.digit[i]%=10000;
		}
		sum.intSize=i;
		if (c!=0)
			sum.digit[sum.intSize++]=c;
		return sum;
	}
	BigInt operator*(int x)const{//contain int2BigInt()
		BigInt pro;
		pro.initBigInt();
		if (x==0){				//防止当x=0时return一个值为0但intSize!=0的BigInt 
			pro.int2BigInt(0); 				
			return pro;			
		}
		int c=0;
		int i;
		for (i=0;i<intSize;i++){
			pro.digit[i]=digit[i]*x+c;
			c=pro.digit[i]/10000;
			pro.digit[i]%=10000;
		}
		pro.intSize=i;
		while (c>0){
			pro.digit[pro.intSize++]=c%10000;
			c/=10000;
		}
		return pro;
	}
	int operator%(const int x)const{//x<10000 
		int temp,c=0;
		for (int i=intSize-1;i>=0;i--){
			temp=digit[i]+c*10000;
			c=temp%x;
		}
		return c;
	}
	bool operator<(const BigInt a)const{
		bool cmp=true;
		if (intSize<a.intSize)
			cmp=true;
		else if (intSize>a.intSize)
			cmp=false;
		else {
			for (int i=intSize-1;i>=0;i--){
				if (digit[i]<a.digit[i]){
					cmp=true;
					break;
				}
				else if (digit[i]>a.digit[i]){
					cmp=false;
					break;
				}
			}
		}
		return cmp;
	}
	void print(){
		for (int i=intSize-1;i>=0;i--){
			cout<<setfill('0')<<setw(i==intSize-1?0:4)<<digit[i];
		}
		cout<<endl;
	}
}; 

struct Edge{
	int start,end;
	BigInt weight;
	Edge(){
	}
	Edge(int start,int end,BigInt weight){
		this->start=start;
		this->end=end;
		this->weight=weight;
	}
	bool operator<(const Edge e){//useless
		return weight<e.weight;
	}
}; 
struct Vex{
	int root;
	Vex(){//initiate root
		this->root=-1;
	} 
};
struct Graph{ //顶点下标从0开始 
	int graphSize;
	vector<Edge> edge[MAXSIZE];
	vector<Vex> vex;
	int initGraph(int graphSize){
		this->graphSize=graphSize;
		for (int i=0;i<graphSize;i++)
			edge[i].clear();
		vex.clear();
	}
	int findRoot(int x){//useless
		if (vex[x].root==-1)
			return x;
		else 
			return vex[x].root=findRoot(vex[x].root);
	}
	int unionSet(int x,int y){//useless
		int xroot=findRoot(x);
		int yroot=findRoot(y);
		if(xroot!=yroot){//if x&y are not in the same set 那么说明其中一个还是初态,一次都没有并过
			vex[xroot].root=yroot; //merge xset into yset 
			return yroot;
		} 
		return -1;
	}
};

int main(){
	int n,m,x;
	Graph graph;
	int start,end;
	BigInt weight;
	bool mark[MAXSIZE];
	BigInt dist[MAXSIZE];
	int newPoint,minDistVex;
	BigInt temp,outputCmp;
	outputCmp.int2BigInt(100000);
	while (cin>>n>>m){//n vexes ,m edges
		//initiate
		graph.initGraph(n);
		newPoint=0;
		for (int i=0;i<graph.graphSize;i++){
			mark[i]=false;
			dist[i].int2BigInt(-1);
		}
		mark[newPoint]=true;
		dist[newPoint].int2BigInt(0);
		//input edge
		for (int i=0;i<m;i++){
			cin>>start>>end;
			weight.int2BigInt(1);//cal weight
			for (int j=0;j<i;j++)
				weight=weight*2;
			graph.edge[start].push_back(Edge(start,end,weight));
			graph.edge[end].push_back(Edge(end,start,weight));
		}
		//process
		for (int time=0;time<n-1;time++){//每趟循环找出x到一个结点的最短路径,共n-1趟 
			//遍历newPoint直接相邻的结点,修改其dist
			for (int i=0;i<graph.edge[newPoint].size();i++){
				int end=graph.edge[newPoint][i].end;
				if (mark[end]==true)//if end结点已经在x集合中,则跳过此次循环 
					continue;
				temp=dist[newPoint]+graph.edge[newPoint][i].weight;
				if (temp<dist[end]||dist[end].digit[0]==-1) //if the new dist< the old dist
					dist[end]=temp;
			}
			//遍历dist,从mark为false的结点中找出其dist最小的结点,确定为新的newPoint,并加入x集合 
			int i;
			for (i=0;i<graph.graphSize;i++){//initiate minDistVex
				if (mark[i]==false&&dist[i].digit[0]!=-1){
					minDistVex=i;
					break;
				}
			}
			for (i++;i<graph.graphSize;i++){
				if (mark[i]==false&&dist[i].digit[0]!=-1&&dist[i]<dist[minDistVex])
					minDistVex=i;
			} 
			newPoint=minDistVex;
			mark[minDistVex]=true;
		} 
		//output. output dist[]
		for (int i=1;i<graph.graphSize;i++){
			if (outputCmp<dist[i])
				cout<<dist[i]%100000<<endl;
			else
				dist[i].print();
		}
	}
	return true;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值