0w1

UVA 1508 Equipment ( DFS )

UVa Online Judge
題目大意是給 n ≤ 10000個五元組,求取 k個的情況下每個位置的最大值相加的值最大。
感覺就只能暴搜,但五元組數量太多,裸裸的 2^10000剪枝也沒有希望。想一下,浪費時間是因為其實真正會用到的五元組不多,更仔細想想,會用到的定義是將用到的那些格子封鎖,確定為最大值,所以實際上我們可以對那五元做枚舉。對於每個五元組,生成其所有子集表示哪些會當作是最大值,然後預處理出取五元組中的每個子集最好可以得到多少分。接下來就能用暴搜,每次至少少去原本五元中一元,複雜度大大進步。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e4 + 4;

int bit(int x){ return 1 << x; }
int bitcount(int x){ return x == 0 ? 0 : bitcount( x >> 1 ) + ( x & 1 ); }

int n, k;
int r[MAXN][5];

int sum[MAXN][1 << 5];
int mxsum[1 << 5];

int dfs(int took, int S, int v){
    if( took == k ) return v;
    int best = 0;
    for(int S0 = S; S0 > 0; S0 = ( S0 - 1 ) & S)
        best = max<int>( best, dfs( took + 1, S - S0, v + mxsum[S0] ) );
    return best;
}

void solve(){
    for(int i = 0; i < n; ++i){
        memset( sum[i], 0, sizeof(sum[i]) );
        for(int j = 0; j < bit( 5 ); ++j)
            for(int g = 0; g < 5; ++g)
                if( j & ( 1 << g ) )
                    sum[i][j] += r[i][g];
    }
    for(int j = 0; j < bit( 5 ); ++j){
        mxsum[j] = 0;
        for(int i = 0; i < n; ++i)
            mxsum[j] = max<int>( mxsum[j], sum[i][j] );
    }
    int ans = dfs( 0, bit( 5 ) - 1, 0 );
    printf("%d\n", ans);
}

int main(){
    int T; scanf("%d", &T);
    while( T-- ){
        scanf("%d%d", &n, &k);
        for(int i = 0; i < n; ++i)
            for(int j = 0; j < 5; ++j)
                scanf("%d", &r[i][j]);
        solve();
    }
    return 0;
}