LDUOJ- 1.27 -F. 膜方俱樂部(tarjan縮點/dp/DAG)
阿新 • • 發佈:2021-01-28
題目描述:
第一行為一個正整數 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];
}