タイトル
彼の夢の中で、TTの願いが叶い、ニャースターのリーダーになりました。ニャースターには1からNまでの番号が付けられたN個の商業都市があり、そのうち1個の都市はTTが位置する都市、つまり首都です。
Meow Starには、商業都市が互いに通信するためのM方向の道路があります。しかし、Meowstarのビジネスの繁栄に伴い、一部の道路は非常に混雑しています。TTが悩んでいる間、彼の魔法のキティは解決策を思いつきました!TTは、このプログラムの新しいポリシーを受け入れ、公表します。
具体的なポリシーは次のとおりです。繁栄を示すために、各商業都市に正の整数をマークします。各猫が道路に沿って1つの商業都市から別の商業都市まで歩くとき、TTはそれらに課金します(目的地の繁栄-出発点)繁栄)^ 3税。
TTはこのポリシーが妥当かどうかをテストするつもりなので、首都から他の都市に移動するために支払う必要のある税額を知りたいと思っています。合計金額が3未満または届かない場合は、静かに「?」と入力してください。
入力
最初の行にTと入力します。これは、Tセットのデータがあることを示します。(1 <= T <= 50)
各データセットについて、最初の行にNを入力してポイント数を示します。(1 <= N <= 200)
2行目にN個の整数を入力します。これは、1からNポイントまでの重みa [i]を表します。(0 <= a [i] <= 20)
3行目にMを入力して、有向道路の数を示します。(0 <= M <= 100000)
次のM行には、各行に2つの整数ABがあり、AからBへの方向道路があることを示しています。
次に、整数Qが与えられ、問い合わせの数を示します。(0 <= Q <= 100000)
各問い合わせはPを与えます。これは、ポイント1からポイントPまでの最小税を見つけることを意味します。
アウトプット
各クエリは1行を出力し、到達できない場合、または税金が3未満の場合、「?」を出力します。
入力例
2
5
6 7 8 9 10
6
1 2
2 3
3 4
1 5
5 4
4 5
2
4
5
10
1 2 4 4 5 6 7 8 9 10
10
1 2
2 3
3 1
1 4
4 5
5 6
6 7
7 8
8 9
9 10
2
3 10
サンプル出力
Case 1:
3
4
Case 2:
?
?
アイデア
税金はマイナスになる可能性があるため、マイナスの権力側があり、これはマイナス側で最短の単一ソース質問・利用SPFA。
出力「?」には3つのケースがあります。
- 到達不能
- 最短経路は存在しません
- 最短経路が3未満(問題)
コード内の対応する状況は次のとおりです。
- プッシュ[V] = INF
- cnt [v]> = nは、負のリングを見つけることです。負のリングが配置されている接続グラフ内のすべてのポイント
- dis [v] <3
SPFA
- ベルマンフォードアルゴリズム:最短経路の数は点の数よりも少ないため、グラフの各エッジで緩和を実行し、緩和点数-1ラウンド。
- Bellman-fordのキュー最適化アルゴリズム-SPFA。
- ベルマンフォードのリラクゼーションプロセスでは、リラクゼーション操作は正常に緩和された最短経路の先頭ノードを持つノード上:Sに隣接する点は緩和されます->最短経路の最初のエッジ;最初のラウンドに隣接する点は緩和されます-最短経路の2番目のエッジ; ...
- したがって、SPFAでは、効果的な緩和操作のみが毎回実行されます。キューを作成してキューに格納するすでにリラックス毎回、チームリーダーからポイントを取り、その隣人をリラックス隣接するポイントがリラックスしている場合は、キューに追加されます。
- 図に負のリングがある場合、負のリングに沿って歩き続けることができ、最短経路長は負の無限大となり、意味がありません。単一ソースの最短経路の問題を解く場合、グラフのエッジの重みが負でない場合、追加の問題を考慮する必要はありません。負の重みのエッジが含まれている場合は、SPFAによって検出された最短経路が有効かどうかを考慮する必要があります。
- 判断ネガティブリング:判断ポイントエンキュー、あるポイントがチームに参加した場合n回、次に説明する負のリング。
コード
#include <cstdio>
#include <cstring>
#include <math.h>
#include <queue>
using namespace std;
const int inf=1e8;
int t,n,m,q,p,tot,head[205],aa[205],dis[205],inq[205],cnt[205];
bool vis[205];
queue<int> que;
struct edge{
int to,w,next=-1;
}e[100005];
void add(int x,int y,int z){
e[++tot].to=y;
e[tot].w=z;
e[tot].next=head[x];
head[x]=tot;
}
void dfs(int s){
vis[s]=false;
for(int i=head[s];i!=-1;i=e[i].next){
if(vis[e[i].to])
dfs(e[i].to);
}
}
void spfa(int s){
dis[s]=0;
inq[s]=1;
que.push(s);
while (!que.empty()) {
int u=que.front();que.pop();
inq[u]=0;
for(int i=head[u];i!=-1;i=e[i].next){
int v=e[i].to;
if(!vis[v])//不可到达
continue;
if(dis[v]>dis[u]+e[i].w){
cnt[v]=cnt[u]+1;
dis[v]=dis[u]+e[i].w;
if(cnt[v]>=n){//找到负环
dfs(v);
}
if(!inq[v]){
que.push(v);
inq[v]=1;
}
}
}
}
}
int main(){
scanf("%d",&t);
for(int i=0;i<t;i++){
memset(vis, true, sizeof(vis));
scanf("%d",&n);
for(int j=0;j<=n;j++){
head[j]=-1;
dis[j]=inf;
inq[j]=0;
cnt[j]=0;
aa[j]=0;
}
for(int j=1;j<=n;j++)
scanf("%d",&aa[j]);
scanf("%d",&m);
tot=0;
for(int j=0;j<m;j++){
int a,b;
scanf("%d%d",&a,&b);
add(a, b, pow(aa[b]-aa[a],3));
}
spfa(1);
scanf("%d",&q);
printf("Case %d:\n",i+1);
for(int j=0;j<q;j++){
scanf("%d",&p);
if(!vis[p]||dis[p]<3||dis[p]==inf)
printf("?\n");
else
printf("%d\n",dis[p]);
}
}
}