1. 程式人生 > 其它 >LDUOJ- 1.27 -F. 膜方俱樂部(tarjan縮點/dp/DAG)

LDUOJ- 1.27 -F. 膜方俱樂部(tarjan縮點/dp/DAG)

技術標籤:訓練圖論dfs

題目描述:

第一行為一個正整數 N。
第二行有N個非負整數A[i],表示了每個分部的orzFang價值。
第三行有N個正整數F[i],表示通過第i個分部的蟲洞所到達的分部為 F[i],可能出現 F[i]=i的情況。

求:
從第 i 個分部出發,orzFang 價值之和的最大值為多少。

題目思路:

對於每個點 都有一個目標點,所以是一個有環的有向圖
可以先縮點

void tarjan(int u) {
	low[u] = dfn[u] = ++indexx;
	vis[u] =1,sta[++top] = u;
	for(int i=head[u]; ~i; i=
e[i].next) { int v = e[i].v; if(!dfn[v]) tarjan(v),low[u] = min(low[u],low[v]); else if(vis[v]) low[u] = min(low[u],low[v]); } if(low[u]==dfn[u]) { int yy; num++; do { yy = sta[top],id[yy] = num,nval[num]+=val[yy],top--,vis[yy] =0 ; } while(yy!=u); } }

這樣這張圖就變成了一張有向無環圖
下面就是喜聞樂見的DAG上dp 了

因為從一個點出發後的到達一個點 -這樣一定能形成一條鏈
對於鏈上的每個點的求解可以用字首和解決
所以在縮完點之後的新圖 要反向建圖

void DP_ON_DAG() {
	queue<int>q;
	for(int i=1 ; i<=num; i++) 	if(deg[i]==0) q.push(i),dp[i]  =nval[i];
	while(q.size()) {
		int u = q.front();
		q.pop();
		int val = nval[u];
		for(int i=head[u]; ~i; i=e[i].next) {
			int  v=
e[i].v; deg[v]--; dp[v] = dp[u]+nval[v]; if(deg[v]==0) { q.push(v); } } } }

當然也可以不反向建圖,跑一個dfs就可以

int  dfs(int u) {
	if(dp[u]) return dp[u];
	dp[u] = nval[u];
	for(int i = head[u]; ~i; i=e[i].next) {
		int v = e[i].v;
		dp[u]+=dfs(v);
	}
	return dp[u];
}