dp[i][j]代表选了i个人,D(J)-P(J)的值为j的状态下,D(J)+P(J)的最大和。
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; const int MAXN = 810; int n, m; int dp[24][MAXN]; int path[24][MAXN]; int P[210], D[210]; int sub[210], sum[210]; int maxval, fix; int ans[210]; bool IfHave( int i, int j, int k ) { while ( i > 0 ) { if ( path[i][j] == k ) return true; j -= sub[ path[i][j] ]; --i; } return false; } void DP() { memset( dp, -1, sizeof(dp) ); dp[0][0+fix] = 0; for ( int i = 1; i <= m; ++i ) for ( int j = -fix; j <= fix; ++j ) { if ( dp[i - 1][j + fix] >= 0 ) { for ( int k = 1; k <= n; ++k ) { int newdp = dp[i - 1][ j+fix ]+sum[k]; int &curdp = dp[i][ j+fix+sub[k] ]; if ( !IfHave( i-1, j+fix, k) && newdp > curdp ) { path[i][j+fix+sub[k]] = k; curdp = newdp; } } } } return; } void getPath( int i, int j ) { int cnt = 0; while ( i > 0 ) { ans[cnt++] = path[i][j]; j -= sub[ path[i][j] ]; --i; } return; } int main() { int cas = 0; while ( scanf( "%d%d", &n, &m ) == 2 && (n || m) ) { for ( int i = 1; i <= n; ++i ) { scanf( "%d%d", &P[i], &D[i] ); sub[i] = P[i] - D[i]; sum[i] = P[i] + D[i]; } fix = 20 * m; maxval = 2 * fix; DP(); int anssub, anssum; for ( int i = 0; i <= fix; ++i ) if ( dp[m][fix-i] >= 0 || dp[m][fix+i] >= 0 ) { if ( dp[m][fix-i] > dp[m][fix+i] ) { anssub = fix-i; anssum = dp[m][fix-i]; } else { anssub = fix+i; anssum = dp[m][fix+i]; } break; } getPath( m, anssub ); int sum1 = 0, sum2 = 0; for ( int i = 0; i < m; ++i ) { sum1 += P[ ans[i] ]; sum2 += D[ ans[i] ]; } printf( "Jury #%d ", ++cas ); printf( "Best jury has value %d for prosecution and value %d for defence: ", sum1, sum2 ); sort( ans, ans + m ); for ( int i = 0; i < m; ++i ) printf( " %d", ans[i] ); puts(" "); } return 0; }