状态压缩DP模型
291. 蒙德里安的梦想
https://www.acwing.com/problem/content/293/

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int N=12,M=1<<N;
int n,m;
LL f[N][M];
vector<int >state[M];//保存可以转移的状态
bool st[N];
int main(){
while(cin>>n>>m,n || m){
for(int i=0;i<1<<n;i++){
int cnt=0;
bool is_valid=true;
for(int j=0;j<n;j++){
if(i>>j&1){
if(cnt&1){
is_valid=false;
break;
}
cnt=0;
}
else cnt++;
}
if(cnt&1){
//这里是出现的最后一个1到末尾也不能出现奇数0
is_valid=false;
}
st[i]=is_valid;
}
for(int i=0;i<1<<n;i++){
state[i].clear();
for(int j=0;j<1<<n;j++){
if((i&j)==0 && st[i|j]){//i,j不能相同 i,j后不能出现奇数个0
state[i].push_back(j);
}
}
}
memset(f,0,sizeof f);
f[0][0]=1;
for(int i=1;i<=m;i++){
for(int j=0;j<1<<n;j++){
for(auto k :state[j]){
f[i][j] += f[i - 1][k];
}
}
}
cout << f[m][0] << endl;
}
return 0;
}
// freopen("testdata.in", "r", stdin);
1064. 小国王
https://www.acwing.com/problem/content/1066/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int N=15,M=1<<10,K=105;
int n,m;
int cnt[M];
vector<int>state;
vector<int>head[M];
LL f[N][K][M];
bool check(int state){//判断有没有相邻的1
for(int i=0;i<n;i++){
if((state>>i&1) && (state>>i+1&1)){
return false;
}
}
return true;
}
int count(int state){//计算1的个数
int num=0;
for(int i=0;i<n;i++){
num+=state>>i&1;
}
return num;
}
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(check(a|b) && (a&b)==0){//判断两行的状态有无根据题目条件
head[i].push_back(j);
}
}
}
f[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=count(state[a]);
if(j>=c){
f[i][j][state[a]]+=f[i-1][j-c][state[b]];
}
}
}
}
}
cout<<f[n+1][m][0]<<endl;
return 0;
}
// freopen("testdata.in", "r", stdin);
327. 玉米田
https://www.acwing.com/problem/content/329/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int M=1<<13,mod=1e8;
int n,m;
int a[15];
vector<int>state;
vector<int>head[M];
int f[15][M];
bool check(int state){
for(int i=0;i+1<m;i++){
if((state>>i&1) && (state>>i+1&1)) return false;
}
return true;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=0;j<m;j++){
int t;
cin>>t;
a[i]+=!t*(1<<j);
}
}
for(int i=0;i<1<<m;i++){
if(check(i)){
state.push_back(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)){
head[i].push_back(j);
}
}
}
f[0][0]=1;
for(int i=1;i<=n+1;i++){
for(int j=0;j<state.size();j++){
if(!(state[j]&a[i])){
for(int k:head[j]){
f[i][state[j]]=(f[i][state[j]]+f[i-1][state[k]])%mod;
}
}
}
}
cout << f[n + 1][0] << endl;
return 0;
}
// freopen("testdata.in", "r", stdin);
292. 炮兵阵地
https://www.acwing.com/problem/content/294/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int M=1<<11;
int f[2][M][M];//f(i,j,k) 已经摆好i行 第i行状态是k 第i-1行是j
int n,m;
int w[105];
vector<int>state;
int cnt[M];
bool check(int s){
for(int i=0;i<m;i++){
if((s>>i&1) && ((s>>i+1&1) ||(s>>i+2&1))) return false;
}
return true;
}
int count(int s){
int num=0;
for(int i=0;i<m;i++){
num+=s>>i&1;
}
return num;
}
int main(){
cin>>n>>m;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
char c;
cin>>c;
if(c=='H') w[i]+=1<<j;
}
}
for(int i=0;i<1<<m;i++){
if(check(i)){
state.push_back(i);
cnt[i]=count(i);
}
}
for(int i=0;i<n+2;i++){
for(int j=0;j<state.size();j++){//c第i行 b第i-1行 a第i-2行
for(int k=0;k<state.size();k++){
for(int u=0;u<state.size();u++){
int a=state[u],b=state[j],c=state[k];
if((a&b) || (a&c) || (b&c)) continue;//判断是否重叠
if(w[i]&c) continue;
f[i&1][j][k]=max(f[i&1][j][k],f[i-1&1][u][j]+cnt[c]);
}
}
}
}
cout<<f[n+1&1][0][0]<<endl;
return 0;
}
// freopen("testdata.in", "r", stdin);
91. 最短Hamilton路径
https://www.acwing.com/problem/content/description/93/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int N=20,M=1<<21;
int f[M][N];//f(i,j) 状态表示为i,走到j的最小值
int n;
int w[25][25];
int main(){
cin>>n;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>w[i][j];
}
}
memset(f,0x3f,sizeof f);
f[1][0]=0;
for(int i=0;i<1<<n;i++){
for(int j=0;j<n;j++){
if(i>>j&1){
for(int k=0;k<n;k++){
if(i>>k&1){
f[i][j]=min(f[i][j],f[i-(1<<j)][k]+w[k][j]);
}
}
}
}
}
cout<<f[(1<<n)-1][n-1]<<endl;
return 0;
}
// freopen("testdata.in", "r", stdin);

浙公网安备 33010602011771号