二进制枚举:
void binary_enum(int n){
for(int i=0;i<(1<<n);i++){//枚举0到2^n-1的状态
for(int j=0;j<n;j++){
if(i&(1<<j)){
}else{
}
}
}
}
__builtin_popcount(i) 统计i二进制中1的个数
牛客练习赛58 C-矩阵消除游戏
思路:
二进制枚举
优化:
这里要注意不能枚举所有的行和列,枚举完行的个数为tot,接下来选剩下(k-tot)个最大的列的和即可,否则会TLE。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const double eps = 1e-10;
const int INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
const ll maxn = 1e6 + 5;
int n,m,k;
int e[30][30];
int s[30];
int main(){
ll sum=0;
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>e[i][j];
sum+=e[i][j];
}
}
k=min(k,min(n,m));
if(k==min(n,m)){
cout<<sum;
return 0;
}
int ans=0;
for(int i=0;i<(1<<m);i++){
int tot=__builtin_popcount(i);
memset(s,0,sizeof(s));
if(tot>k) continue;
int res=0;
for(int j=0;j<n;j++){
for(int t=1;t<=m;t++){
if((1<<j)&i) res+=e[j+1][t];//选中的行记入res求和
else s[t]+=e[j+1][t];//未选中的记入列的和
}
}
sort(s+1,s+1+m,greater<int>());//剩下的列排个序选大的
for(int j=1;j<=k-tot;j++){
res+=s[j];
}
ans=max(ans,res);
}
cout<<ans;
return 0;
}
HDU5616
思路:
二进制枚举 or 01背包dp
坑点:
两者相减的重量也可以称出来,set会超时。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const double eps = 1e-10;
const int INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
const ll maxn = 1e6 + 5;
int n,m;
int w[30];
bool vis[2005];
void ***(){
for(int i=0;i<(1<<n);i++){
int sum=0;
for(int j=0;j<n;j++){
if(i&(1<<j)) sum+=w[j];
}
vis[sum]=1;
for(int j=0;j<n;j++){
if(sum-w[j]>=0) vis[sum-w[j]]=1;
}
}
}
void solve(){
memset(vis,0,sizeof(vis));
cin>>n;
for(int i=0;i<n;i++){
cin>>w[i];
}
***();
cin>>m;
while(m--){
int x;
cin>>x;
if(vis[x]){
cout<<"YES\n";
}
else cout<<"NO\n";
}
}
int main(){
int T;cin>>T;
while(T--){
solve();
}
return 0;
}