状态压缩--动态规划

状态压缩也就是把多个状态都转译成一个状态,由于题目的题意就是需要一步一步递推也就是dp,但是常规的dp只能计算一个状态,无法满足多个状态,所以可以使用状态压缩.

将这多个状态划分为二进制形式:设有m个状态,那么所有的可能状态为 2m ,如果有4个状态,0010 表示只满足了第二个状态,依次类推

但是可以看出,输出的不可能存在一个都不满足的状态,所以计算时状态总数为 2m1 

状态合并: 使用 |,将两个状态的1合并

 

 题目描述

糖果店的老板一共有 M 种口味的糖果出售。为了方便描述,我们将 M 种口味编号 1M

小明希望能品尝到所有口味的糖果。遗憾的是老板并不单独出售糖果,而是 K 颗一包整包出售。

幸好糖果包装上注明了其中 K 颗糖果的口味,所以小明可以在买之前就知道每包内的糖果口味。

给定 N 包糖果,请你计算小明最少买几包,就可以品尝到所有口味的糖果。

## 输入格式

第一行包含三个整数 NMK

接下来 N 行每行 K 这整数 T1,T2,,TK,代表一包糖果的口味。

## 输出格式

一个整数表示答案。如果小明无法品尝所有口味,输出 1

样例 #1

样例输入 #1

```
6 5 3
1 1 2
1 2 3
1 1 3
2 3 5
5 4 2
5 1 2
```

样例输出 #1

```
2
```

把输出的每个包装里面都计算出所含的糖果状态,然后进行dp即可,时间复杂度 O(n2m)

#include<bits/stdc++.h> using namespace std; const int N=500; int n,m,k; int f[1<<25],candy[1<<25]; bool vis[1<<25]; int main() { cin>>n>>m>>k; for(int i=1;i<=n;i++){ int num=0; for(int j=1;j<=k;j++){ cin>>num; candy[i]=candy[i]|1<<(num-1); vis[candy[i]]=true,f[candy[i]]=1; } } for(int i=1;i<=n;i++) for(int j=1;j<1<<(m+1);j++) if(vis[j]){ if(!vis[j|candy[i]]) f[j|candy[i]]=f[j]+1; else f[j|candy[i]]=min(f[j|candy[i]],f[j]+1); vis[j|candy[i]]=true; } if(!vis[(1<<m)-1]) cout<<-1; else cout<<f[(1<<m)-1]<<endl; return 0; }

 

1 //https://www.luogu.com.cn/problem/P1433 2 3 //将所有的奶酪看做成状态,0为未被吃,1为被吃 4 //枚举所有的状态,f[i][j]表示,在吃到第i个奶酪下,没有吃到j奶酪的距离 5 //用i对所有的j全都更新一边最短距离即可 6 #include<bits/stdc++.h> 7 using namespace std; 8 const int N=5e4+10; 9 int n,m; 10 double f[25][N],dis[500][500]; 11 double x[N],y[N],res=2e9; 12 double distance_(double x1,double x2,double y1,double y2) 13 { 14 return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); 15 } 16 int main() 17 { 18 cin>>n; 19 for(int i=1;i<=n;i++) cin>>x[i]>>y[i]; 20 x[0]=y[0]=0; 21 for(int i=0;i<=n;i++) 22 for(int j=i+1;j<=n;j++) dis[j][i]=dis[i][j]=distance_(x[i],x[j],y[i],y[j]); 23 memset(f,0x7f,sizeof f); 24 for(int i=1;i<=n;i++) f[i][1<<(i-1)]=dis[0][i]; 25 for(int k=1;k<(1<<n);k++){ 26 for(int i=1;i<=n;i++){ 27 if(!(k&1<<(i-1))) continue; 28 for(int j=1;j<=n;j++){ 29 if(!(k&1<<(j-1))||i==j) continue; 30 f[i][k]=min(f[i][k],f[j][k-(1<<(i-1))]+dis[j][i]); 31 } 32 } 33 } 34 for(int i=1;i<=n;i++) res=min(res,f[i][(1<<n)-1]); 35 printf("%.2lf",res); 36 return 0; 37 }

 

//https://www.luogu.com.cn/problem/P1896 //压状dp //由于时间复杂度达到了指数级复杂度,所以搜索不能进行 //考虑动态规划,dp i,j,k表示 第i行,使用了j个国王,此时的状态是k // 对于第i行,若要求此时符合条件,有: 第i行中的棋子,两两互不相邻,即check(a|b)=true // 对于第i-1行,有与第i行的国王不相邻,所以使用&运算即可 #include<bits/stdc++.h> using namespace std; const int N=12,M=1<<10,K=110; int n,m,cnt[M],dp[N][M][K]; vector<int>state,head[M];//把状态存入state中 int count(int x)//计算1的个数 { int res=0; for(int i=0;i<n;i++) if((x>>i&1)==1) res++; return res; } bool check(int x) //检查相邻两位是否连续为1 { for(int i=0;i<n;i++) if((x>>i&1)&&(x>>i+1&1)) return false; return true; } int main() { cin>>n>>m; for(int i=0;i<1<<n;i++) if(check(i)) state.push_back(i),cnt[i]=count(i); for(int i=0;i<state.size();i++) for(int j=0;j<state.size();j++){ int a=state[i],b=state[j]; if(!(a&b)&&check(a|b)) head[i].push_back(j); } dp[0][0][0]=1; for(int i=1;i<=n+1;i++) for(int j=0;j<=m;j++) for(int a=0;a<state.size();a++) for(int b:head[a]){ int c=cnt[state[a]]; if(j>=c) dp[i][j][a]+=dp[i-1][j-c][b]; } cout<<dp[n+1][m][0]; return 0; }

 


__EOF__

本文作者Sakurajimamai
本文链接https://www.cnblogs.com/o-Sakurajimamai-o/p/17673963.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   o-Sakurajimamai-o  阅读(52)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 因为Apifox不支持离线,我果断选择了Apipost!
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· Trae 开发工具与使用技巧
-- --
点击右上角即可分享
微信分享提示