HDU - 2844 - 코인 (복수 배낭 바이너리 최적화)

링크 제목
제목 효과 : 동전의 다른 교단의 여러 조각의 주어진 여러 가지 조합이 동전은 범위가 1 ~ m에서 서로 다른 교단의 많은 종류로 구성 될 수 요청합니다.
  표면은 여러 배낭의 매우 일반적인 문제이지만, 데이터는 직접 떨어져 멀티 배낭을 사용할 수 있도록하지 않는 것. 이진 최적화 : 그것은 배낭 최적화 기법의 배수이어야한다. 우리는 다수 넣어 \ N- (\) 로 분할이 \ (1,2,4,8 ··· \)\ (K \) ,이 간격으로 표현 될 수있다 (나머지의 분할 수) \ ([1, N ] \) 의 수 내의 모든. 이유는 무엇입니까? 상기의 수보다 커야 이진 동일해야하므로 \ (K \) 경우 \ (K는 \) 가 큰 이진수 찢어 될 수있는 경우보다 크다. 이후 이진수 앞에 표현할 수 \ ([1, NK] \ ) 의 수 플러스 (진 각도를 알 수있다) \ (K는 \) 로 표현 될 수있다 \ ([1, N] \) 의 수이다.
  너무 오래 우리의 이전 기사의 첫 번째 몇 가지 전처리를 수행한다. 그것이 돈의 총 가치보다 작은 경우 단일 항목에 직접 목록에있는 항목과 전체 배낭으로, 단어의 번호가 있습니다. 숫자가 자신의 돈의 총 가치보다 작은 경우, 바이너리 최적화에 넣어 것은 실행하려면 항목의 수에 분할입니다 \ (01 \) 배낭. 마지막으로, 다른 교단의 통계는 모든 항목은 행의 수를 만들 수 있습니다.

const int maxn = 1e5+10;
int coin[105], c[105];
bool dp[maxn];
int main(void) {
    int n, m;
    while(~scanf("%d%d", &n, &m) && (n||m)) {
        zero(dp); dp[0] = 1;
        for (int i = 1; i<=n; ++i) scanf("%d", &coin[i]);
        for (int i = 1; i<=n; ++i) {
            scanf("%d", &c[i]);
            if (coin[i]*c[i]>=m)
                for (int k = coin[i]; k<=m; ++k) //完全背包
                    dp[k] |= dp[k-coin[i]];
            else {
                for (int j = 1; c[i]>=j; j<<=1) { //对多重背包进行二进制优化
                    for (int k = m; k>=coin[i]*j; --k)
                        dp[k] |= dp[k-coin[i]*j];
                    c[i]-=j;
                }
                if (c[i]) 
                    for (int k = m; k>=coin[i]*c[i]; --k)
                        dp[k] |= dp[k-coin[i]*c[i]];
            }
        }
        int sum = 0;
        for (int i = 1; i<=m; ++i) sum += dp[i];
        printf("%d\n", sum);
    }
    return 0;
}

추천

출처www.cnblogs.com/shuitiangong/p/12660977.html