HAOI2010 軟件安裝
阿新 • • 發佈:2018-10-19
tac top tin node min 差異 turn http putchar
傳送門
一開始我以為這道題是一個比較正常的分組背包,只不過原來做的題目的限制條件是數目,這次是有體積(軟件所占空間)的限制,但是兩者好像沒什麽差異……
於是我就仿著正常的分組背包寫了一下,然後過了樣例。我才不會告訴你我一開始結果全是0,因為我寫錯了
交上去一看只有10分……
回來發現原來這題並沒有說是一棵樹……orz,那我們來看一看每一個環,每個環裏面所有的軟件要麽全選,要麽全不選,所以直接看成一個強連通分量縮點,把體積和價值都合起來即可。就像爐石那張融合所以我們縮點,之後把所有入度為0的點向虛擬節點連邊,之後開始正常DP。但是我一開始發現建出來的圖是反的,這樣就行不成樹了。不過想起了tarjan求強連通分量的時候,因為我把樹建成了有向圖,所以肯定原來的起點現在還應該是起點,就把建圖反了過來,之後就神奇的AC啦!
看一下代碼。
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<set> #include<queue> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar(‘\n‘) usingnamespace std; typedef long long ll; const int M = 1005; const int INF = 1000000009; const ll mod = 1e9+7; int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < ‘0‘ || ch > ‘9‘) { if(ch == ‘-‘) op = -1; ch = getchar(); } while(ch >= ‘0‘ && ch <= ‘9‘) { ans *= 10; ans += ch - ‘0‘; ch = getchar(); } return ans * op; } struct node { int next,to,from; }e[M<<1]; int m,n,dp[M][M],v[M],x,y,head[M],ecnt,size[M],w[M],dfn[M],scc[M],idx,low[M],stack[M],top,cnt; int rdeg[M],tot; bool vis[M]; void add(int x,int y) { e[++ecnt].to = y; e[ecnt].next = head[x]; e[ecnt].from = x; head[x] = ecnt; } void tarjan(int x) { low[x] = dfn[x] = ++idx; stack[++top] = x,vis[x] = 1; for(int i = head[x];i;i = e[i].next) { if(!dfn[e[i].to]) tarjan(e[i].to),low[x] = min(low[x],low[e[i].to]); else if(vis[e[i].to]) low[x] = min(low[x],dfn[e[i].to]); } if(low[x] == dfn[x]) { int p; cnt++; while((p = stack[top--])) { scc[p] = cnt,vis[p] = 0,v[cnt] += v[p],w[cnt] += w[p]; if(p == x) break; } } } void rebuild() { rep(i,1,ecnt) { int r1 = scc[e[i].from],r2 = scc[e[i].to]; if(r1 != r2) add(r2,r1),rdeg[r1]++; } rep(i,n+1,cnt) { dp[i][0] = v[i]; if(!rdeg[i]) add(0,i); } } void dfs(int x,int fa) { for(int i = head[x];i;i = e[i].next) { int t = e[i].to; if(t == fa) continue; dfs(t,x); per(j,m,1) { rep(p,0,j-w[t]) dp[x][j] = max(dp[x][j],dp[x][j-p-w[t]] + dp[t][p]); } //rep(j,0,m) printf("%d ",dp[x][j]);enter; //printf("#%d %d\n",x,dp[x][0]); } } int main() { n = read(),m = read(); rep(i,1,n) w[i] = read(); rep(i,1,n) v[i] = read(); rep(i,1,n) { x = read(); if(x != 0) add(i,x); } cnt = n,tot = ecnt; rep(i,1,n) if(!dfn[i]) tarjan(i); rebuild(); //rep(i,tot+1,ecnt) printf("%d %d\n",e[i].from,e[i].to); dfs(0,0); printf("%d\n",dp[0][m]); return 0; }
HAOI2010 軟件安裝