2020年冬休み[gmoj1595] [GDKOIトレーニング] [通行料金] [フロイド最短ルート(バリアント)]

タイトルの説明

他の皆と同じように、ファーマージョンは私に世界の牛をニンで飼うように教え、世界の牛に私の素晴らしい精神を任せました。幸運をもたらすために、彼は一連の規則と規制を設定しました、それで農場の道を歩くどんな牛も農民ジョンに料金を払わなければならないように。

ファーム内には、N(1 <= N <= 250)草原(1〜Nのラベルが付いている)があり、M(1 <= M <= 10000)草原A_jとB_j(1 <= A_j <=を結ぶ双方向の道路があります。 N; 1 <= B_j <= N)。牛はどの草のどの部分からでも草に届きます。FJは、A_jとB_jを接続する双方向道路に通行料L_j(1 <= L_j <= 100,000)を設定しました。

同じ2つの草原を結ぶ道路が複数ある場合がありますが、草原と草原自体を結ぶ道路はありません。最も幸いなことは、牛はどの牧草地からでも開始でき、一連の道をたどって他の牧草地に到達できることです。

貪欲であることを除いて、私たち(牛)は何と言っていいのかわかりません。FJは各草に通行料C_i(1 <= C_i <= 100000)を設定しました。芝生から別の芝生へのコストは、通過するすべての道路の通行料と、通行するすべての芝生の最大通行料の合計です(始点と終点を含む)。

働き者の牛は、どの道を選ぶべきか調査したいと考えています。彼らは、K(1 <= K <= 10,000)の質問を受け入れ、各クエリの最小コストを出力するプログラムを作成することを望んでいます。i番目の質問には、2つの数値s_iとt_i(1 <= s_i <= N; 1 <= t_i <= N; s_i!= T_i)が含まれ、これは開始と終了の草原を表します。

5つの芝生フィールドがある次のサンプル画像を考えてみます。
ここに画像の説明を挿入

草原1から草原3への道路の「側方通行料金」は3、草原2の「ポイント通行料金」は5です。

草原1から草原4に移動するには、草原1から草原3、草原5まで歩いて、最後に草原4に到達できます。このようにすると、必要な「サイド料金」は2 + 1 + 1 = 4で、必要なポイント料金は4(草5の最大ポイント料金)なので、合計コストは4 + 4 = 8になります。

草地2から草地3への最良の道は、草地2から始まり、草地5に到達し、最後に草地3に到達することです。このようにすると、通行料は3 + 1 = 4、通行料は5、合計コストは4 + 5 = 9になります。

入力

1行目:スペースで区切られた3つの整数:N、M、K
2行目からN + 1行目:1
目i + 1には1つの整数が含まれています:C_i Lines N + 2 to N + M + 1 :行j + N + 1には、スペースで区切られた3つの整数が含まれています:A_j、B_j、L_j
行N + M + 2反転行N + M + K + 1:行i + N + M + 1は、質問i、スペースで区切られた2つの整数s_iとt_iが含まれています

アウトプット

1行目からK行目:行iには、s_iからt_iまでの最小コストを表す単一の整数が含まれています。

入力例

5 7 2
2
5
3
3
4
1 2 3
1 3 2
2 5 3
5 3 1
5 4 1
2 4 3
3 4 4
1 4
2 3

出力例

8
9

分析

この問題は2点間の最短経路を見つけることであり、特に最短経路はエッジの重みと最大の点の重みとして定義されます。(n≤250)

Problem Solution:マルチソースの最短回路はフロイです。最初ポイントの重みを並べ替え、転送ポイントの重みがエンドポイントの重みよりも小さい場合に大きい場合に列挙します。これは、転送ポイントがパス上の最大の重みを持つポイントであることを示し、この時点で回答を更新できます。
Floydが見つけた各中間点kについて、点の重みの最大値はi、j、およびkでなければなりませんkは小さいものから大きいものへと列挙されるため、現在のパスでは、開始点iと終了点jを除いて、kは最大のポイントウェイトを持つポイントです。

コードオン

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int f[251][251],dis[251][251],g[251],s[251];
int n,m,p,q,t;
inline bool cmp(int x,int y)
{
	return g[x]<g[y];	
}
int main()
{
	freopen("toll.in","r",stdin);
	freopen("toll.out","w",stdout);
	cin>>n>>m>>p; 
	memset(f,1,sizeof(f));
	memset(dis,1,sizeof(dis));
	for(int i=1;i<=n;i++) 
	{
		s[i]=i;
		cin>>g[i];
		f[i][i]=g[i];		
	}	
	sort(s,s+n+1,cmp);
	for(int i=1;i<=m;i++)
	{
		int a,b,c;
		cin>>a>>b>>c;
		dis[a][b]=dis[b][a]=min(dis[a][b],c);
	}	
	for(int k=1;k<=n;k++)
	{
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				dis[s[i]][s[j]]=min(dis[s[i]][s[j]],dis[s[i]][s[k]]+dis[s[k]][s[j]]);	
				f[s[i]][s[j]]=min(f[s[i]][s[j]],dis[s[i]][s[j]]+max(g[s[i]],max(g[s[k]],g[s[j]])));	
				/*算上i,j,k中最大点权*/						
			}
		}	
	}	
	for(int i=1;i<=p;i++)
	{
		cin>>q>>t;
		if(f[q][t]>=16843010) cout<<-1<<endl;
		else cout<<f[q][t]<<endl; 
	}
	fclose(stdin);
	fclose(stdout);
	return 0;
}
元の記事110件を公開 100 件を獲得 8016件を訪問

おすすめ

転載: blog.csdn.net/dglyr/article/details/105056891