bzoj 1017: [JSOI2008]魔獸地圖DotR
阿新 • • 發佈:2018-12-23
樹形DP
大部分都是抄的黃學長的部落格
後來實在查不出錯 乾脆連變數照著一起改了。。。
/************************************************************** Problem: 1017 User: lxy8584099 Language: C++ Result: Accepted Time:8176 ms Memory:59680 kb ****************************************************************/ /* P[] 表示力量 L[]表示數量上限 M[]表示花費 每個裝備建一個樹 然後和在一個節點上 f[i][j][k] 表示第i個裝備 j個用於合成另一個裝備 花費了k元 所得的最大力量 dp[i][j] 表示前i個裝備 花費j元 所得的最大力量 此處的裝備應該只高階裝備 低階裝備會算進高階裝備裡面 我們有 dp[num][j]=max{dp[num-1][k]+f[i][l][j-k]} 一共是 i,j,k,l 四重迴圈 i是第幾個高階裝備 j是前i裝備一共花費 k是前i-1類裝備的花費 c是這個裝備裡有多少用於合成其他裝備 每個高階裝備是樹根 兒子們是合成它所要的低階裝備 處理每一個高階裝備 有 g[i][j] 表示此裝備的錢i個兒子 花費j的錢 所獲得的最大力量 那麼g[i][j]=max{g[i-1][j-k]+f[v][l*need][k]} 有 i,j,k,l四層迴圈 i表示前i個兒子 j表示總共花費 l表示合成多少個該裝備 k表示合成該裝備的花費 v表示兒子節點 need表示合成一個該裝備需要多少這個兒子 之後列舉合成的l個物品中有j個是直接用於增加力量的 剩餘的參加合成 f[i][j][k] =max{g[num][k]+P[i]*(l-j)} 其中num是指所有兒子 處理每一個低階裝備 列舉用來合成的 和剩下直接加力量的 dp一遍就return*/ #include<cstdio> #include<cstring> #define inf (0x3fffffff) #define max(a,b) ((a>b)?(a):(b)) #define min(a,b) ((a>b)?(b):(a)) using namespace std; const int N=60,NN=2050; struct pp {int v,need,nxt;} e[NN*10]; int n,m,tot,P[N],L[N],M[N],head[N],du[N]; int f[N][2*N][NN],g[N][NN],dp[N][NN];char str[6]; void add(int u,int v,int need) { e[++tot].nxt=head[u];head[u]=tot; e[tot].v=v;e[tot].need=need;du[v]++; } void init() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&P[i]); scanf("%s",str); if(str[0]=='A') { int num;scanf("%d",&num); for(int j=1,v,need;j<=num;j++) scanf("%d%d",&v,&need),add(i,v,need); } else scanf("%d%d",&M[i],&L[i]); } } void DP(int x) { if(!head[x]) // 此為基礎裝備 { L[x]=min(L[x],m/M[x]); for(int i=0;i<=L[x];i++) //用於合成 for(int j=i;j<=L[x];j++) // (j-i)用於直接加力量 f[x][i][j*M[x]]=(j-i)*P[x]; return ; // 這裡更新 f 錯寫成了M[i] ... } L[x]=inf; // 高階裝備無限制! for(int j=head[x];j;j=e[j].nxt) { int v=e[j].v,need=e[j].need;DP(v); L[x]=min(L[x],L[v]/need); // 更新L[x] 要合成當然取最小啦 M[x]+=need*M[v]; } // 這裡更新高階裝備的 L 和 M L[x]=min(L[x],m/M[x]); memset(g,~0x3f,sizeof(g)); g[0][0]=0; for(int l=L[x];l>=0;l--) { int num=0; for(int i=head[x];i;i=e[i].nxt) { int v=e[i].v,need=e[i].need; num++; // g[i][j]=max{g[i-1][j-k]+f[v][l*need][k]} for(int j=0;j<=m;j++) for(int k=0;k<=j;k++) g[num][j]=max(g[num][j],g[num-1][j-k]+f[v][l*need][k]); // 這裡計算該裝備的g } // f[i][j][k] =max{g[num][k]+P[i]*(l-j)} for(int j=0;j<=l;j++) for(int k=0;k<=m;k++) f[x][j][k]=max(f[x][j][k],g[num][k]+P[x]*(l-j)); // 這裡更新 f 剩下l-j就是用來直接加力量的了 } } void solve() { memset(f,~0x3f,sizeof(f)); int num=0,ans=0; for(int i=1;i<=n;i++) if(!du[i]) // 只對高階裝備 dp { DP(i); num++;// dp[num][j]=max{dp[num-1][k]+f[i][l][j-k]} for(int j=0;j<=m;j++) for(int k=0;k<=j;k++) for(int l=0;l<=L[i];l++) dp[num][j]=max(dp[num][j],dp[num-1][k]+f[i][l][j-k]); } for(int i=0;i<=m;i++) ans=max(ans,dp[num][i]); printf("%d\n",ans); } int main() { init(); solve(); return 0; }