Ideal Path, NEERC 2010, UVa1599 (題解+隨機測試資料)
阿新 • • 發佈:2019-01-22
題意簡述:一張n個頂點(1~n)m條邊的無向圖,每條邊有顏色(用整數表示),保證存在從1到n的路徑。要求給出從1出發到達n的最優路徑:經過的邊數最少,如果存在多種這樣的走法,則取其中經過邊的顏色序列按字典序最小的路徑。輸出這一顏色序列。分析:m的上限為200000,用BFS求最短路徑,時間複雜度為O(m)。為了先得到所有的最短路徑,從節點n開始“倒序”BFS,記錄下每個節點i走到n的最短路程dis[i]。這樣從1出發按每步dis減少1的路徑走,必然能沿所有的最短路到達n。記錄下dis以後,從節點1開始BFS。存下每一步“減1走法”中顏色最小(可能有多種)的走法(具體實現見程式碼中的vector<int>next和vector<int>newnext),將顏色序列存到ans陣列中最後列印。程式碼 :
測試資料生成程式碼://Ideal Path //Yhq #include<cstdio> #include<cstring> #include<vector> #include<queue> #include<cmath> #define maxn 100005 #define maxm 200005 #define inf 1<<30 using namespace std; int n, m; struct edge { int node1, node2, color; edge(int n1, int n2, int n3): node1(n1), node2(n2), color(n3) {} }; bool vis[maxn]; int dis[maxn]; vector<int> graph[maxn], ans; //graph[i][j]=p, 則edges[p].node1==i; //ans記錄最短路徑顏色 vector<edge> edges; void reset() { memset(vis, false, sizeof(vis)); memset(dis, inf, sizeof(dis)); for (int i=0; i<maxn; ++i) graph[i].clear(); edges.clear(); ans.clear(); } void build (int n1, int n2, int c) { edges.push_back(edge(n1,n2,c)); graph[n1].push_back( (edges.size()-1) ); } //從終點n開始倒著bfs, 記錄每個節點到終點的最短路程dis void rev_bfs() { vis[n]=true; dis[n]=0; queue<int> que; que.push(n); while (!que.empty()) { int last=que.front(); que.pop(); for (int i=0; i<graph[last].size(); ++i) { edge ed = edges[graph[last][i]]; if (!vis[ed.node2]) { vis[ed.node2]=true; dis[ed.node2]=dis[last]+1; que.push(ed.node2); } } } printf("%d\n",dis[1]); } // 從起點0開始, 找所有dis下降為1的路徑,從中選擇顏色編號最小的路徑前進 // (多條路徑顏色相同時全部要搜尋下一層比較),直到終點n. void bfs() { vector<int> next; next.push_back(1); vis[1]=true; for (int i=1; i<=dis[1]; ++i) { int min_c=inf; for (int j=0; j<next.size(); ++j) { int k=next[j]; for (int p=0; p<graph[k].size(); ++p) { int tmp=graph[k][p]; if (!vis[edges[tmp].node2] && dis[edges[tmp].node2]-dis[k]==-1) { min_c= min (min_c, edges[tmp].color); } } } ans.push_back(min_c); vector<int> newnext; for (int j=0; j<next.size(); ++j) { int k=next[j]; for (int p=0; p<graph[k].size(); ++p) { int tmp=graph[k][p]; if (!vis[edges[tmp].node2] && dis[edges[tmp].node2]-dis[k]==-1 && edges[tmp].color==min_c) { newnext.push_back(edges[tmp].node2); vis[edges[tmp].node2]=true; } } } next=newnext; } } int main () { //freopen("IdealPath.txt","w",stdout); while (scanf ("%d%d",&n,&m)==2) { reset(); for (int i=1; i<=m; ++i) { int n1, n2, c; scanf("%d%d%d",&n1,&n2,&c); build(n1,n2,c); build(n2,n1,c); } rev_bfs(); memset(vis,false,sizeof(vis)); bfs(); for (int i=0; i<ans.size(); ++i) { printf("%d",ans[i]); if (i<ans.size()-1) printf(" "); else printf("\n"); } } return 0; }
修改數值上限MAXN, MAXM, COLOR, TESTNUM;測試資料會生成到IDEALPATH.txt檔案。
#include<cstdio> #include<ctime> #include<cstdlib> #include<iostream> #define TESTNUM 100 #define MAXN 100 #define MAXM 200 #define COLOR 10 using namespace std; int main () { freopen("IDEALPATH.txt","w",stdout); srand ( (unsigned int) time(NULL) ); //code here int testnum=TESTNUM; while (testnum--) { int colornum=rand()%COLOR+2; int n=rand()%MAXN + 2; int m=rand()%MAXM +3; cout<<n<<" "<<m<<endl; int t1=1, t2=2; while (t2<n) { if (m==1) { cout<<t1<<" "<<n<<" "<<rand()%colornum<<endl; --m; break; } t2=rand()%(n-t1)+t1+1; cout<<t1<<" "<<t2<<" "<<rand()%colornum<<endl; --m; t1=t2; } for (int i=1; i<=m; ++i) { cout<<rand()%n+1<<" "<<rand()%n+1<<" "<<rand()%colornum<<endl; } cout<<endl; } return 0; }