1. 程式人生 > 其它 >【模擬試題】旅行

【模擬試題】旅行

Description

  X先生來到了一個奇怪的國家旅行。這個國家有N個城市,每個城市均有且僅有一個機場,但是這機場所有航班只飛往一個城市。每個城市有一個遊覽價值,第i個城市的遊覽價值為A[i]。
現在他想知道,從第i個城市出發,並只坐飛機飛往下一個城市,遊覽價值之和最多是多少(一個城市遊覽多次只計算1次遊覽價值)

Input

  輸入檔案travel.in的第1行為一個正整數N。
  第2行有N個非負整數A[i],表示了每個城市的遊覽價值。
  第3行有N個正整數F[i],表示第i個城市的航班飛往的城市為F[i],可能出現F[i]=i的情況。

Output

  輸出檔案travel.out包括N行,第i行包含一個非負整數,表示從第i個城市出發遊覽價值之和的最大值為多少。

Sample Input

8
5 4 3 2 1 1 1 1
2 3 1 1 2 7 6 8

Sample Output

12
12
12
14
13
2
2
1


思路

  • tarjan縮點然後拓撲序,完了
  • 看起來沒有c++程式碼的題解,來發一篇

程式碼

#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
const int maxn=200003;
queue<int> q;
vector<int> e[maxn];
int n,nxt[maxn],val[maxn],cnt,num,w[maxn],r[maxn];
int dfn[maxn],low[maxn],top,vis[maxn],s[maxn],bel[maxn];
void tarjan(int x){
	dfn[x]=low[x]=++cnt,vis[x]=1,s[++top]=x;
	int v=nxt[x];
	if(!dfn[v]) tarjan(v),low[x]=min(low[x],low[v]);
	else if(vis[v]) low[x]=min(low[x],dfn[v]);
	if(dfn[x]==low[x]){
		++num;
		do{vis[s[top]]=0,w[num]+=val[s[top]],bel[s[top--]]=num;}while(x!=s[top+1]);
	}
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d",&val[i]);
	for(int i=1;i<=n;++i) scanf("%d",&nxt[i]);
	for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
	for(int i=1;i<=n;++i) if(bel[i]!=bel[nxt[i]]) ++r[bel[i]],e[bel[nxt[i]]].push_back(bel[i]);
	for(int i=1;i<=num;++i) if(!r[i]) q.push(i);
	while(!q.empty()){
		int x=q.front(); q.pop();
		for(int i=0;i<e[x].size();++i){
			if(!--r[e[x][i]]) q.push(e[x][i]);
			w[e[x][i]]+=w[x];
		}
	}
	for(int i=1;i<=n;++i) cout<<w[bel[i]]<<'\n';
	return 0;
}