1. 程式人生 > >bzoj 1017: [JSOI2008]魔獸地圖DotR

bzoj 1017: [JSOI2008]魔獸地圖DotR

 

樹形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; }