7-35 城市间紧急救援 (25 分)(思路加详解)
一:題目
作為一個城市的應(yīng)急救援隊伍的負(fù)責(zé)人,你有一張?zhí)厥獾娜珖貓D。在地圖上顯示有多個分散的城市和一些連接城市的快速道路。每個城市的救援隊數(shù)量和每一條連接兩個城市的快速道路長度都標(biāo)在地圖上。當(dāng)其他城市有緊急求助電話給你的時候,你的任務(wù)是帶領(lǐng)你的救援隊盡快趕往事發(fā)地,同時,一路上召集盡可能多的救援隊。
輸入格式:
輸入第一行給出4個正整數(shù)N、M、S、D,其中N(2≤N≤500)是城市的個數(shù),順便假設(shè)城市的編號為0 ~ (N?1);M是快速道路的條數(shù);S是出發(fā)地的城市編號;D是目的地的城市編號。
第二行給出N個正整數(shù),其中第i個數(shù)是第i個城市的救援隊的數(shù)目,數(shù)字間以空格分隔。隨后的M行中,每行給出一條快速道路的信息,分別是:城市1、城市2、快速道路的長度,中間用空格分開,數(shù)字均為整數(shù)且不超過500。輸入保證救援可行且最優(yōu)解唯一。
輸出格式:
第一行輸出最短路徑的條數(shù)和能夠召集的最多的救援隊數(shù)量。第二行輸出從S到D的路徑中經(jīng)過的城市編號。數(shù)字間以空格分隔,輸出結(jié)尾不能有多余空格。
輸入樣例:
4 5 0 3
20 30 40 10
0 1 1
1 3 2
0 3 3
0 2 2
2 3 2
結(jié)尾無空行
輸出樣例:
2 60
0 1 3
結(jié)尾無空行
二 思路:
dij算法,加了其他判斷方法
三 上碼:
//有相同的的路徑時 選擇 頂點人數(shù)最多的 #include<stdio.h> #include<stdlib.h> #define infinite 99999 typedef struct GNode* PtrGNode; typedef struct GNode{int Nv;int Ne;int GData[1000][1000]; }gnode; int begin,end,a[1000];//a數(shù)組存每個城市的救援隊人數(shù); int path[1000]={-1}; void CreatGNode(PtrGNode G){int i,j,w,k;scanf("%d%d%d%d",&G->Nv,&G->Ne,&begin,&end);for(i=0;i<G->Nv;i++){scanf("%d",&a[i]);}for(i=0; i<G->Nv;i++){for(j=0;j<G->Nv;j++){if(i == j)G->GData[i][j] = 0;elseG->GData[i][j] = infinite;}}for(k=0; k<G->Ne; k++){scanf("%d%d%d",&i,&j,&w);G->GData[i][j] = w;G->GData[j][i] = w;} } void outprint(PtrGNode G){int i,j;for(i=0;i<G->Nv;i++){for(j=0;j<G->Nv;j++){if(G->GData[i][j]!=infinite)printf("%d ",G->GData[i][j]);elseprintf("∞");}printf("\n");} }void putlu(int u,int v) {//通過v結(jié)點的上一結(jié)點查找到u結(jié)點,將路徑存到棧s中,最后輸出。 int s[60],k,i,l;k=0;l=path[v];//將3對應(yīng)的上一個點1 入棧了 然而3并沒有進(jìn)數(shù)組 while(l!=u)//入棧 {s[k++]=l;l=path[l];}printf("%d ",u);for(i=k-1;i>=0;i--)printf("%d ",s[i]);printf("%d",v);//3沒有進(jìn)數(shù)組 }void Dijkstra(PtrGNode G){int dist[1000];//存路徑長度int cist[1000];//記錄人數(shù) 一直在變 int rist[1000];//存人數(shù) 到達(dá)每個頂點的人數(shù)不變 int vis[1000]={0};//記錄已經(jīng)遍歷的點int count[1000]; //記錄最短路徑條數(shù) int i,j;//因為從begin開始的點 也有人數(shù)if(G->Nv==2){//最短路徑只有兩個頂點 cist[end]=a[0]+a[1];count[end]=1;path[1]=0;}else{for(i=0;i<G->Nv;i++){count[i]=1;dist[i] = G->GData[begin][i];if(i != begin)cist[i] = a[begin]+a[i];elsecist[i] = a[i];}vis[0]=1;while (1){int mv=-1;int min=infinite;for(i=0; i<G->Nv; i++){if(vis[i] != 1 && dist[i] < min){min=dist[i];mv=i;}}if(mv==-1)break;vis[mv]=1;for(j=0;j<G->Nv;j++){if(vis[j]!=1 && min+G->GData[mv][j]<dist[j]){dist[j] = min+G->GData[mv][j];cist[j] = cist[mv]+a[j];//根據(jù)路徑長度已經(jīng)判斷 比原來路徑短 而其人數(shù)必定時增加的 // rist[j]=rist[mv]+a[j]; count[j] = count[mv];path[j] = mv;}else if(vis[j]!=1 && min+G->GData[mv][j] == dist[j]){//處理相同路徑長度時 選擇人數(shù)多的count[j] += count[mv]; if((cist[mv]+a[j])>cist[j]){ cist[j] = cist[mv]+a[j];// rist[j]=rist[mv]+a[j]; //更新 已經(jīng)找到最短路徑的那一個頂點 已經(jīng)確認(rèn)的到達(dá)這個頂點的總?cè)藬?shù) path[j] = mv;}}}} }printf("%d %d",count[end],cist[end]);printf("\n");putlu(begin,end);} int main(){PtrGNode G;G=(PtrGNode)malloc(sizeof(struct GNode));CreatGNode(G);Dijkstra(G);//outprint(G); } //2 1 0 1 //20 30 //0 1 2//6 9 0 3 //10 20 30 40 50 60 //0 1 1 //0 2 3 //0 3 6 //0 4 3 //0 5 2 //1 2 2 //2 3 3 //3 4 3 //4 5 1四:上超時的碼(這是我二刷是做的,上面是第一次做的)
但這個超時間。我優(yōu)化了但還是過去
/**思路:這個就是單源點最短路徑的變形,這里是出現(xiàn)了到達(dá)某個頂點出現(xiàn)相同的最短距離,只不過是經(jīng)過的點不一樣,每個點給了相應(yīng)的賦值,我們需要判斷每一條路徑上經(jīng)過的點,他們的值相加(每個點賦值),比較最大的那個就是救援隊人數(shù)最多的,選取他們作為救援最優(yōu)路徑 */ #include<bits/stdc++.h> using namespace std;#define infinite 9999 typedef struct GNode* PtrGraph; typedef struct GNode{int Nv;int Ne;int Date[501][501]; }gnode;int N,M,S,D; map<int,int>m;//用map容器進(jìn)行儲存每個結(jié)點的救援隊數(shù)量 int path[501] = { S };//將路徑的初始值設(shè)為開始的那個點 //鄰接矩陣儲存圖 void createGraph(PtrGraph G){cin >> N >> M >> S >> D;G->Nv = N;G->Ne = M;for( int i = 0; i < N; i++ ){int temp;cin >> temp;m[i] = temp; }//矩陣初始化for( int i = 0; i < G->Nv; i++ ){for( int j = 0; j < G->Nv; j++ ){if( i == j )G->Date[i][j] = 0;elseG->Date[i][j] = infinite; }}//矩陣賦值for( int i = 0; i < G->Ne; i++ ){int a,b,c;cin >> a >> b >> c; G->Date[a][b] = c;G->Date[b][a] = c;} } //輸出矩陣 void outPutGNode(PtrGraph G){int i,j;for(i=0; i<G->Nv; i++){for(j=0;j<G->Nv;j++){if(G->Date[i][j] == infinite||G->Date[j][i] == infinite)printf("∞");elsecout << G->Date[i][j] << ' ';}printf("\n");} } //求路徑上救援隊數(shù)量 int PathSum( int x ){int sum = m[x];while( path[x] != x ){x = path[x];sum+=m[x];}return sum; } //求路徑 void PathWay(int x){stack<int>s;s.push(x);while(path[x] != x ){x = path[x];s.push(x); }while( !s.empty() ){if( s.size() != 1 )cout << s.top() << ' ';elsecout << s.top();s.pop(); }} //單源點最短路徑 void dij(PtrGraph G){int dist[501] = {0};int visited[501] = {0};int vis[501] = {0}; // int path[501] = { S };//將路徑的初始值設(shè)為開始的那個點 int count[501];//記錄路數(shù) for( int i = 0; i < G->Nv; i++ ){count[i] = 1;//初始化為1,即開始點到每個點的路數(shù)為1條 dist[i] = G->Date[S][i];//將開始的那一行賦值給dist }visited[S] = 1;vis[S] = 1;while(1){int m = -1;int min = infinite;//求取最小值 for(int i = 0; i < G->Nv; i++ ){if( dist[i] < min && visited[i] != 1){min = dist[i];m = i;} }//說明沒找到最小值 即代表訪問完了,即便圖是不連通的 那也求不出最小值了 if( m == -1 ){break; }visited[m] = 1; //更新 for( int i = 0; i < G->Nv; i++ ){if( visited[i] != 1 && dist[m] + G->Date[m][i] < dist[i] ){dist[i] = dist[m] = G->Date[m][i];path[i] = m; count[i] = count[m];//如果從開始的點S到 m 有兩條路,那么在更新最短路徑時 //需要經(jīng)過m的話,那么m的路數(shù)將賦值給 更新的結(jié)點 } } }//這個循環(huán)主要是處理相同的最短路徑 while(1){int m = -1;int min = infinite;//求取最小值 for(int i = 0; i < G->Nv; i++ ){if( dist[i] < min && vis[i] != 1){min = dist[i];m = i;} }//說明沒找到最小值 即代表訪問完了,即便圖是不連通的 那也求不出最小值了 if( m == -1 ){break; }vis[m] = 1; //出現(xiàn)相同的路徑 for( int i = 0; i < G->Nv; i++ ){if( vis[i] != 1 && dist[m] + G->Date[m][i] == dist[i] ){ count[i] = count[i] + count[m];//更新路數(shù) int temp = path[i];//將原來路徑存下來,萬一相等的路徑,沒有原來的路徑上救援隊人數(shù)多 還可以改回來 int a = PathSum(i);path[i] = m;int b = PathSum(i);if( a > b ){//原來的路徑人數(shù)多 path[D] = temp;//改回原來的路徑 } } } }int Sumrescue = PathSum(D);//救援隊數(shù)量 cout << count[D] << ' ' << Sumrescue << endl;PathWay(D);}int main(){PtrGraph G = (PtrGraph)malloc(sizeof (struct GNode));createGraph(G);dij(G);} //4 5 0 3 //20 30 40 10 //0 1 1 //1 3 2 //0 3 3 //0 2 1 //2 3 2//6 8 0 3 //10 20 30 40 50 60 //0 1 1 //0 2 3 //0 3 6 //0 4 3 //0 5 2 //1 2 2 //3 4 3 //4 5 1加油boy!
總結(jié)
以上是生活随笔為你收集整理的7-35 城市间紧急救援 (25 分)(思路加详解)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何使用PQ分区魔术师
- 下一篇: 电动平板车的维护保养方案电动汽车维保方案