- 题目描述:
-
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
思路:long long 存储路径长度将会发生溢出,所以我们采用高精度。与平时高精度表示不同的是:这次大数将用2进制数表示。#include<cstdio> #include<cstring> #include<queue> #include<vector> using namespace std; const int MAXN=505; const int MOD=100000; struct Edge{ int to; int mark[MAXN]; Edge(){} Edge(int to,int w) { memset(mark,0,sizeof(mark)); this->to=to; mark[w]=1; } }; vector<Edge> mp[MAXN]; int n,m; int d[MAXN][MAXN]; int vis[MAXN]; bool judge(int now,Edge e) { int to=e.to; int sum[MAXN]={0}; for(int i=0;i<MAXN-1;i++) { int x=(d[now][i]+e.mark[i]+sum[i]); sum[i]=x%2; sum[i+1]+=x/2; } for(int i=MAXN-1;i>=0;i--) { if(d[to][i]>sum[i]) return true; if(d[to][i]<sum[i]) return false; } return false; } void sign(int now,Edge e) { int sum[MAXN]={0}; for(int j=0;j<MAXN-1;j++) { int x=(d[now][j]+e.mark[j]+sum[j]); sum[j]=x%2; sum[j+1]+=x/2; } for(int j=0;j<MAXN;j++) d[e.to][j]=sum[j]; } void spfa(int s) { for(int i=0;i<n;i++) { for(int j=0;j<MAXN;j++) { d[i][j]=1; } vis[i]=0; } for(int i=0;i<MAXN;i++) { d[s][i]=0; } queue<int> que; que.push(s); vis[s]=1; while(!que.empty()) { int now=que.front();que.pop(); vis[now]=0; for(int i=0;i<mp[now].size();i++) { Edge e=mp[now][i]; if(judge(now,e)) { sign(now,e); if(!vis[e.to]) { vis[e.to]=1; que.push(e.to); } } } } for(int i=1;i<n;i++) { int s=0; for(int j=0;j<MAXN;j++) { if(d[i][j]==1) { s++; } } if(s==MAXN) printf("-1 "); else { int res=0; int k=1; for(int j=0;j<MAXN;j++) { if(d[i][j]==1) { res+=k; res%=MOD; } k*=2; k%=MOD; } printf("%d ",res%MOD); } } } int main() { while(scanf("%d%d",&n,&m)!=EOF) { for(int i=0;i<n;i++) mp[i].clear(); for(int i=0;i<m;i++) { int u,v; scanf("%d%d",&u,&v); mp[u].push_back(Edge(v,i)); mp[v].push_back(Edge(u,i)); } spfa(0); } return 0; }