【一隻蒟蒻的刷題歷程】 【PTA】 A1087 通往羅馬的道路

確實,從我們的城市到羅馬有許多不同的旅遊路線。您應該以最低的成本找到客戶的路線,同時獲得最大的幸福。

輸入規格:

每個輸入文件包含一個測試用例。對於每種情況,第一行均包含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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章