確實,從我們的城市到羅馬有許多不同的旅遊路線。您應該以最低的成本找到客戶的路線,同時獲得最大的幸福。
輸入規格:
每個輸入文件包含一個測試用例。對於每種情況,第一行均包含2個正整數N(2≤N≤200)(城市數)和K(城市對之間的路線總數);然後是起始城市的名稱。接下來的N-1行分別給出一個城市的名稱和一個整數,代表一個人可以從該城市(起始城市除外)獲得的幸福。然後是K行,每行以City1 City2 Cost格式描述兩個城市之間的路線。這裏的城市名稱是由3個大寫英文字母組成的字符串,目的地始終是代表羅馬的ROM。
輸出規格:
對於每個測試用例,我們都應該找到成本最低的路線。如果這樣的路線不是唯一的,那麼將建議人們獲得最大的幸福。如果這樣的路線仍然不是唯一的,那麼我們輸出的平均幸福感最大-法官保證這樣的解決方案存在並且是唯一的。
因此,在輸出的第一行中,您必須打印4個數字:建議路線的成本最小,成本,幸福度和平均幸福度(僅取整數部分)的不同路線數。然後在下一行中,您應該以City1-> City2-> …-> ROM格式打印路線。
Sample Input:
6 7 HZH
ROM 100
PKN 40
GDN 55
PRS 95
BLN 80
ROM GDN 1
BLN ROM 1
HZH PKN 1
PRS ROM 2
BLN HZH 2
PKN GDN 1
HZH PRS 1
Sample Output:
3 3 195 97
HZH->PRS->ROM
思路:
應該是目前做過最ex的最短路徑,比(城市緊急救援)還ex!!
優先級:路徑長度(花費) > 點權之和(幸福值) > 平均點權之和
代碼:
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <set>
#include <map>
using namespace std;
struct node{
int v;
int w;
node(int a,int b){v=a;w=b;}
friend bool operator<(node a,node b){
return a.w>b.w;
}
};
const int maxn=250;
const int inf=1<<27; //到達不了
vector<node> g[maxn]; //存圖
priority_queue<node> p; //優先隊列優化
bool vis[maxn]={false}; //是否走過
int n,k;
map<string,int> m1; //道路名稱對應的編號
map<int,string> m2; //編號對應的道路名稱
int weight[maxn]={0},dis[maxn],aveweight[maxn],num[maxn],numweight[maxn];
//點權,距離,平均點權,最短路徑數,總點權
int pre[maxn],cnt[maxn];
//上一個點(記錄路徑),路徑中點的個數
string name;
void dijkstra(int s)
{
fill(dis,dis+maxn,inf);
numweight[s]=0; //初始總點權
cnt[s]=0; //初始路徑中點的個數(不算起點)
dis[s]=0; //初始距離
num[s]=1; //初始路徑數
pre[s]=-1; //起點的上一個頂點設置爲-1
aveweight[s]=0; //初始平均點權
p.push(node(s,0)); //入隊
while(!p.empty())
{
int u=p.top().v; //取出第一個點
p.pop();
if(vis[u]) continue;
vis[u]=1;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i].v;
int w=g[u][i].w;
if(vis[v]==false)
{
if(dis[v]>dis[u]+w) //路徑可優化,其他值全部更新
{
dis[v]=dis[u]+w;
cnt[v]=cnt[u]+1; //路徑中點數增加
numweight[v]=numweight[u]+weight[v];
num[v]=num[u];
pre[v]=u;
}
else if(dis[v]==dis[u]+w) //路徑相等
{
num[v]+=num[u]; //路徑個數更新
if(numweight[v]<numweight[u]+weight[v])
//最大點權和可以更新,其他(除路徑長度)全部更新
{
cnt[v]=cnt[u]+1;//路徑中點數增加
numweight[v]=numweight[u]+weight[v];
pre[v]=u;
}
else if(numweight[v]==numweight[u]+weight[v])
//最大點權和也相等
{
double aveu=(numweight[u]+weight[v])*1.0/(cnt[u]+1);
//通過u到v 的平均點權和
double avev=numweight[v]*1.0/cnt[v];
//不通過u到v 的平均點權和
if(aveu>avev)
//如果可以優化,更新其他內容
{
pre[v]=u;
cnt[v]=cnt[u]+1;
}
}
}
p.push(node(v,dis[v])); //入隊
}
}
}
}
int main()
{
cin>>n>>k>>name;
m1[name]=1; //起點
m2[1]=name;
for(int i=2;i<=n;i++)
{
cin>>name>>weight[i];
m1[name]=i; //地名 - 編號
m2[i]=name; //編號 - 地名
}
string a,b;
int cost;
while(k--)
{
cin>>a>>b>>cost;
g[m1[a]].push_back(node(m1[b],cost)); //無向圖
g[m1[b]].push_back(node(m1[a],cost));
}
dijkstra(1);
int ans=m1["ROM"];
cout<<num[ans]<<" "<<dis[ans]<<" "<<numweight[ans]<<" "<<numweight[ans]/cnt[ans]<<endl;
//輸出路徑數 , 最短距離(花費) , 最大點權和 , 平均點權和
vector<int> path; //存路徑
path.push_back(ans); //加入終點
while(pre[ans]!=-1)
{
path.push_back(pre[ans]); //不斷加入前驅
ans = pre[ans];
}
for(int i=path.size()-1;i>=0;i--) //倒着輸出
{
cout<<m2[path[i]];
if(i>=1) cout<<"->";
}
return 0;
}