(Hui understands) Niuke-Lock (shaped pressure dp)

Topic link

There are n residents in room 106, and each of them has an importance. Several locks can be installed on the door of the room. Suppose there are k locks, named 1 to k. Each lock has a corresponding key, which is also represented by 1 to k. The key can be copied and distributed to any number of residents. Each resident of room 106 holds a number of keys, which is a subset of 1 to k. If the union of the keys of several residents is 1 to k, that is, they have the corresponding keys for all the locks, and they can open the door when they are all present. The new land warfare agreement stipulates that when a group of residents are present, the door can be opened if and only if their importance adds up to at least m. Ask at least how many locks you need to install in room 106. That is, find the smallest k so that each of the residents can be appropriately given several keys (that is, a subset of 1 to k), so that the union of keys held by the set of residents whose sum of importance is less than m is not 1 to k, and the union of keys held by the set of residents whose sum of importance is greater than or equal to m is 1 to k.

Input description: The
first line of two integers n and m, 0<n<21, 0<m<1000000001.
The n integers in the second row represent the importance of the residents.
The importance is between [1,1000000000].
Output description:
An integer indicates the minimum number of locks required.

The problem solution
is really hard to think about. The editor also read a lot of blogs and thought about it for a long time. This problem is not very suitable for us who have only learned the state compression dp. Although the code is a template problem, it is not easy to come up with it. , The price is not high. So let me first talk about the method: we find a set whose importance is less than m, and then after adding any person, his total importance is greater than or equal to m, and the final answer is the number of such sets. Why? We assume that such a set lacks a key, and the importance of another person is greater than m, so another person must have this key, so this key is assigned to these people (that is, all people except this set People, because after adding them, the important value is greater than m), why should this happen? Suppose that after a set (x) plus a person in a set (y), the important value is greater than m (or assume that only one key is missing) At this time, some people may think that the key can be assigned to the people in the y set, but at this time, you see that we add a person other than the y set to the x set. The important value is still less than m (representing the key incomplete). Adding a person's importance value in the y set must be greater than m. If we consider this situation to be equivalent to assigning a key to the people in the y set, then it is clear that this key is redundant. In this case, we will There is no need to consider, so we can draw our above conclusions (that is, find the set whose important value is less than m when there are as many people as possible)

Give me a thumbs up if you understand the
java code

import java.util.*;
public class Main {
    
    
    public static void main(String[] args) {
    
    
    	Scanner sc = new Scanner(System.in);
    	long n,m;
    	final int N=30;
    	long[]a=new long[N];
    	long []dp=new long[1<<21];
    	n=sc.nextLong();
    	m=sc.nextLong();
    	for(int i=0;i<n;i++)
    		a[i]=sc.nextLong();
    	long ans=0;
    	for(int i=0;i<(1<<n);i++) {
    
    
    		boolean flag=true;
    		for(int j=0;j<n;j++) {
    
    
    			if((i&(1<<j))==0) {
    
    
    				dp[i|(1<<j)]=dp[i]+a[j];
                    if(dp[i|(1<<j)]<m)flag=false;
    				
    			}
    		}
    		if(dp[i]<m&&flag)ans++;
    	}
    		
    		System.out.println(ans);	
	
	}
}

c++ code

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,m,i,j,mx,flag,s,nt,a[101],f[1200010],ans;
int main(){
    
    
    scanf("%lld%lld",&n,&m);
    for(i=0;i<n;i++){
    
    
        scanf("%lld",&a[i]);
    }
    mx=1ll<<n;mx--;
    for(s=0;s<=mx;s++){
    
    
        flag=0;
        for(i=0;i<n;i++)if(!(s&(1ll<<i))){
    
    
            nt=s|(1ll<<i);
            f[nt]=f[s]+a[i];
            if(f[nt]<m)flag=1;
        }
        if(!flag&&f[s]<m)ans++;
    }
    printf("%lld",ans);
}

Guess you like

Origin blog.csdn.net/jahup/article/details/105879141