正文

Zoj 1013 Great Equipment2008-02-21 19:09:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/cruxd/32849.html

分享到:

2756964 2008-02-21 18:12:06 Accepted 1013 C++ 00:03.02 2404K C.D.=.=

有点意思的DP题,同样也有不小的难度。

模型大致如下:一组背包,除了体积以外,还有重量的限制。有3种不同的item:比如说一把剑,一件盔甲,一双鞋。他们各自有体积,重量,Def值,而组合到一起——也许叫做不死斗篷,出题者明显是英雄无敌的爱好者——又有新的Def加成。如何得到最大的Def?

对于每一辆车(背包),在装满的情形下,可以得到几组不同的xyz,代表三种装备的数量。假如能够得到所有车子总的xyz组合,这题就迎刃而解了。但是我们不能对100辆车子,对每种xyz之和进行搜索,这样数据量太大。

考虑到题目给出xyz<500,故而建立m[i][x][y]的数组,对前i辆车中的xy进行DP。因为在当前i车中,对于每组ix iy,都有唯一对应的iz(最大)。而只要把这辆车中的ixiy去掉就是前一辆车i-1下的xyz值,所以m[i][x][y] =MAX(m[i - 1][x - ix][y - iy]+iz),ix iy 遍历,表示在前i辆车中z能达到的最大值。从而所有的xyz组合都被记录下来了。这种用N-1维数组记录一个N维组合,然后对其DP求得最后一个数的方法就很棒。

为了节省空间,采用滚动数组。具体代码中把i-1提前,对于i-1下每一组xy,加上这辆车里的ixiy就是当前i组下的xy。

#include <cstdio>
#include 
<string>

#define min(x, y) ( x < y ? x : y )
#define rg(x, y) ( x = ( y > x ? y : x ) )  //replace if greater

int N, c1, c2, c3, def, w[100], s[100], m[2][501][501], cs;
int
 wa, sa, da, wb, sb, db, wc, sc, dc, mx, my;

int
 init ();
void
 dp ();
void
 print ();
void test ( int
 );

int
 main ()
{
    
//freopen ( "in.txt", "r", stdin );

    cs = 0;
    
while
 ( init () )
    
{
        dp ();
        print ();
    }

    
return 0;
}


int init ()
{
    scanf ( 
"%d"&
N );
    
if ( !
N )
    
{
        
return 0
;
    }

    
int i;
    scanf ( 
"%d%d%d"&wa, &sa, &
da );
    scanf ( 
"%d%d%d"&wb, &sb, &
db );
    scanf ( 
"%d%d%d"&wc, &sc, &
dc );
    scanf ( 
"%d%d%d%d"&c1, &c2, &c3, &
def );
    
for ( i = 0; i < N; i ++
 )
    
{
        scanf ( 
"%d%d"&w[i], &
s[i] );
    }

    def 
-= c1 * da + c2 * db + c3 * dc;
    memset ( m, 
0xffsizeof
 ( m ) );
    
return
 N;
}


void dp ()
{
    
int
 i, x, y;
    
int
 rw, rs;
    mx 
= 0, my = 0
;
    m[
0][0][0= 0
;
    
for ( i = 0; i < N; i ++
 )
    
{
        memset ( m[
1], 0xffsizeof ( m[1
] ) );
        
int
 ix, iy, iz, mmx, mmy;
        mmx 
= mx, mmy =
 my;
        
for ( x = 0; x <= mx; x ++
 )
        
{
            
for ( y = 0; y <= my; y ++
 )
            
{
                
if ( m[0][x][y] != -1
 )
                
{
                    
for ( ix = 0; wa*ix <= w[i] && sa*ix <= s[i]; ix ++
 )
                    
{
                        rw 
= w[i] - wa * ix, rs = s[i] - sa *
 ix; 
                        
for ( iy = 0; iy*wb <= rw && iy*sb <= rs; iy ++
 )
                        
{
                            iz 
= min ( ( rw - iy * wb ) / wc, ( rs - iy * sb ) /
 sc );
                            rg ( m[
1][x + ix][y + iy], iz + m[0
][x][y] );
                            rg ( mmx, x 
+
 ix );
                            rg ( mmy, y 
+
 iy );
                        }

                    }

                }

            }

        }

        mx 
= mmx, my = mmy;
        memcpy ( m[
0], m[1], sizeof ( m[1
] ) );
        
//test ( i );

    }

}


void print ()
{
    
int ans = 0
, t;
    
int
 x, y, z;
    
for ( x = 0; x <= mx; x ++
 )
    
{
        
for ( y = 0; y <= my; y ++
 )
        
{
            z 
= m[0
][x][y];
            
if ( z != -1
 )
            
{
                t 
= da * x + db * y + dc *
 z;
                rg ( ans, t );
                
int c = min ( min ( x / c1, y / c2 ), z /
 c3 );
                
if ( def > 0
 )
                
{
                    t 
+= def *
 c;
                }

                rg ( ans, t );
            }

        }

    }

    
if ( cs ++ )
    
{
        printf ( 
"\n"
 );
    }

    printf ( 
"Case %d: %d\n", cs, ans );
}

阅读(5601) | 评论(3)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册