| ||||||||||
| Online Judge | Problem Set | Authors | Online Contests | User | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest | |||||||||
另一种思路,复杂度有点高,但测出来是g++16ms,有闲心的同学可以看看时间复杂度:O(n*sum_of_a) 空间复杂度O(n*sum_of_a)(可以优化到O(sum_of_a)
dp[i][j]:将i~n都卖完并且多买j个最少需要多少钱
初始状态:
dp[n][j] = (an+j+10)*pn (0<=j<=sum_of_a-an)
状态转移:
dp[i][j] = min(
dp[i+1][j+ai], //不买i类
dp[i+1][0]+(ai+j+10)*pi, //买i类
)( 1<=i<=n-1, 0<=j<=sum_of_a-a[i]-a[i+1]-a[i+2]-...-a[n] )
目标状态:
dp[1][0]
证明:
对于当前状态dp[i][j],不可能出现买一部分i又留一部分到后面买,因为如果后面买的那一类是j,
若pi>pj,则全部都到后面买比只在后面买一部分优
若pi<pj,则全部都到这买更优
语文可能比较差,如果看不懂上面的证明,自己想也可以很快出来。
代码:(空间复杂度已优化)
#include <cstdio>
#define Min(a,b) ((a)<(b)?(a):(b))
int n;
int cnt[101], prc[101], scnt;
int dp[100001];
void input() {
scanf( "%d", &n );
scnt = 0;
for( int i=1; i<=n; i++ ) {
scanf( "%d%d", cnt+i, prc+i );
scnt += cnt[i];
}
}
int work() {
scnt -= cnt[n];
for( int j=0; j<=scnt; j++ )
dp[j] = (cnt[n]+10+j)*prc[n];
for( int i=n-1; i>=1; i-- ) {
scnt -= cnt[i];
int dp0 = Min( dp[cnt[i]], dp[0]+(cnt[i]+10)*prc[i] );
for( int j=1; j<=scnt; j++ )
dp[j] = Min( dp[j+cnt[i]], dp[0]+cnt[i]+10+j)*prc[i] );
dp[0] = dp0;
}
return dp[0];
}
int main() {
int T;
scanf( "%d", &T );
while(T--) {
input();
printf( "%d\n", work() );
}
}
Followed by: Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator