• 动态规划--状态压缩


    https://www.acwing.com/problem/content/293/

    给定一个空矩阵,问用1*2的矩形将其填满存在多少种方案。

    可以只考虑一种,如果横的都已经确定了,那么竖的只有0或者1种放法,所以只考虑横的就好了(只考虑竖的也行)

    暴搜复杂度为O(N! * M!),所以只能考虑动态规划,用一个整数表示一列的状态。

    朴素写法:

     1 #include<iostream>
     2 #include<cstring>
     3 using namespace std;
     4 const int N=12,M=1<<12;
     5 long long f[N][M];
     6 bool st[M];
     7 int main(void){
     8     int n,m;
     9     while(cin>>n>>m,n||m){
    10         for(int i=0;i< 1<<n;i++){
    11             int cnt=0;
    12             st[i]=true;
    13             for(int j=0;j<n;j++){
    14                 if(i>>j&1){
    15                     if(cnt&1){
    16                         st[i]=false;
    17                     cnt=0;
    18                     }
    19                 }else{
    20                     cnt++;
    21                 }
    22             }
    23             if(cnt&1){
    24                 st[i]=false;
    25             }
    26         }//预处理全部的状态。
    27         memset(f,0,sizeof f);
    28         f[0][0]=1;
    29         for(int i=1;i<=m;i++){
    30             for(int j=0;j<1<<n;j++){
    31                 for(int k=0;k<1<<n;k++){
    32                     if((j&k)==0&&st[j|k]){
    33                         f[i][j]+=f[i-1][k];
    34                     }
    35                 }
    36             }
    37         }
    38         cout<<f[m][0]<<endl;
    39         
    40     }
    41     return 0;
    42 }

     预处理好j对应的状态

     1 #include<iostream>
     2 #include<cstring>
     3 #include<vector>
     4 using namespace std;
     5 const int N=12,M=1<<12;
     6 long long f[N][M];
     7 bool st[M];
     8 vector<int> state[M];
     9 int main(void){
    10     int n,m;
    11     while(cin>>n>>m,n||m){
    12         for(int i=0;i< 1<<n;i++){
    13             int cnt=0;
    14             st[i]=true;
    15             for(int j=0;j<n;j++){
    16                 if(i>>j&1){
    17                     if(cnt&1){
    18                         st[i]=false;
    19                     cnt=0;
    20                     }
    21                 }else{
    22                     cnt++;
    23                 }
    24             }
    25             if(cnt&1){
    26                 st[i]=false;
    27             }
    28         }//预处理全部的状态。
    29         for(int j=0;j < 1<<n;j++){
    30             state[j].clear();
    31             for(int k=0;k< 1<<n;k++){
    32                 if((j&k)==0&&st[j|k]){
    33                     state[j].push_back(k);
    34                 }
    35             }
    36         }
    37         memset(f,0,sizeof f);
    38         f[0][0]=1;
    39         for(int i=1;i<=m;i++){
    40             for(int j=0;j<1<<n;j++){
    41                 for(auto k:state[j]){
    42                     f[i][j]+=f[i-1][k];
    43                 }
    44             }
    45         }
    46         cout<<f[m][0]<<endl;
    47         
    48     }
    49     return 0;
    50 }

    https://www.acwing.com/problem/content/93/

    最短Hamilton路径,dfs写不了,因为复杂度为O(n!)。

    只能用dp。

     1 #include<iostream>
     2 #include<cstring>
     3 using namespace std;
     4 const int N=20;
     5 int w[N][N];
     6 int f[1<<N][N];
     7 int main(void){
     8     int n;
     9     cin>>n;
    10     for(int i=0;i<n;i++){
    11         for(int j=0;j<n;j++){
    12             cin>>w[i][j];
    13         }
    14     }
    15     memset(f,0x3f,sizeof f);
    16     f[1][0]=0;
    17     //先枚举状态是因为后面需要用到前面的状态
    18     for(int i=0;i<1<<n;i++){//枚举状态
    19         for(int j=0;j<n;j++){//枚举每一个点,如果i中有这个点,就枚举倒数第二个点
    20             if((1<<j)&i){
    21                 for(int k=0;k<n;k++){
    22                     if((1<<k)&i){
    23                         f[i][j]=min(f[i][j],f[i-(1<<j)][k]+w[k][j]);
    24                     }
    25                 }
    26             }
    27         }
    28     }
    29     cout<<f[(1<<n)-1][n-1];
    30     return 0;
    31 }
  • 相关阅读:
    数据结构——数据结构的起源和研究内容
    数据结构——学习数据结构的意义
    C++中动态内存申请的结果
    C++中函数异常规格的说明
    C++异常处理的深入理解
    NOIP 2012 Day2
    NOIP 2012 Day1
    NOIP 2011 Day2
    NOIP 2011 Day 1
    NOIP 2010
  • 原文地址:https://www.cnblogs.com/greenofyu/p/14555712.html
Copyright © 2020-2023  润新知