状态压缩DP专题

来源:互联网 发布:dw给淘宝图片加链接 编辑:程序博客网 时间:2024/05/29 14:55

poj1038
题意:用2*3格子覆盖有禁区的n*m长方形,问最多可以放置多少个格子。
解法:整行覆盖,第二维存储前两行的覆盖状态
dp[i][st]:前i-1行已覆盖完成,且i-1,i-2行的覆盖状态为st,最多可以放置的格子数
dp[i][st]>dp[i+1][st]状态转移通过枚举第i行的覆盖状态完成。注意地图上禁区不能覆盖。
状态设计用三进制存储:
0:前两行均无覆盖
1:i-2行覆盖,i-1行无覆盖
2:i-1行覆盖
枚举时从第0列开始,分三种情况:
1.不填充该格
2.横放2*3格子,以该格为右上角
3.竖放2*3格子,以该格为右上角
然后进行dfs,直到枚举到最后一列,得到最终状态st’,进行状态转移即可

# include<iostream># include<cstdio># include<algorithm># include<queue># include<complex># include<stack># include<math.h># include<cstring>#include<map>#define ll long long#define pi acos(-1)#define MP make_pair#define X first#define Y secondusing namespace std;const int INF = 0x3f3f3f3f;const int maxn = 150+10;const int maxm = 10+10;const int maxst = 60000;int t,n,m;int dp[3][maxst];bool ma[maxn][maxm];int bit[maxm];int three[maxm],ans,cur;void init(){    three[0]=1;    for(int i=1;i<=11;i++) three[i]=three[i-1]*3;}void fenjie(int x,int &y){    for(int i=0;i<m;i++){        bit[i]=x%3;        if(bit[i]!=0)  y+=three[i]*(bit[i]-1);        x/=3;    }}bool d1(int r,int c){//横放地图限制    if(ma[r][c]||ma[r][c+1]||ma[r-1][c]||ma[r-1][c+1]||ma[r-2][c]||ma[r-2][c+1]) return false;    return true;}bool d2(int r,int c){//竖放地图限制    if(ma[r][c]||ma[r-1][c]||ma[r][c+1]||ma[r-1][c+1]||ma[r][c+2]||ma[r-1][c+2]) return false;    return true;}void update(int row,int nowc,int now,int num){    if(nowc>=m){        dp[cur][now]=max(dp[cur][now],num);        return;    }    if(row-2>=0&&nowc+1<m&&bit[nowc]==0&&bit[nowc+1]==0&&d1(row,nowc)){//可以横放            update(row,nowc+2,now+three[nowc]*2+three[nowc+1]*2,num+1);    }    if(row-1>=0&&nowc+2<m&&bit[nowc]!=2&&bit[nowc+1]!=2&&bit[nowc+2]!=2&&d2(row,nowc)){//可以竖放        update(row,nowc+3,now+three[nowc]*2+three[nowc+1]*2+three[nowc+2]*2,num+1);    }    update(row,nowc+1,now,num);//不放}int main(){    init();    //freopen("a.txt","r",stdin);    scanf("%d",&t);    while(t--){        int num;        scanf("%d%d%d",&n,&m,&num);        memset(ma,0,sizeof(ma));        for(int i=1;i<=num;i++){            int x,y;            scanf("%d%d",&x,&y); x--,y--;            ma[x][y]=1;        }        //第一列不放        for(int i=0;i<maxst-3;i++) dp[0][i]=-INF;        dp[0][0]=0; cur=0;        //从第二列开始放置        ans=0;        for(int i=1;i<n;i++){            cur^=1;            for(int j=0;j<maxst;j++) dp[cur][j]=-INF;            for(int j=0;j<three[m];j++){//注意枚举上界不再是(1<<M),不能使用位运算!                if(dp[1-cur][j]==-INF) continue;                int k=0;                fenjie(j,k);                dp[cur][k]=max(dp[cur][k],dp[1-cur][j]);//整行不放                update(i,0,k,dp[1-cur][j]);            }        }        for(int i=0;i<three[m];i++) ans=max(ans,dp[cur][i]);        printf("%d\n",ans);    }    return 0;}

zoj1346
题意:DAG图拓扑排序的个数统计
解法:dp[st]表示还有st状态的点未加入序列时,还能够有的排序方法数
删除已加入的点及相关边,然后枚举当前入度为0的点,加入st状态,记忆化搜索即可
复杂度分析:n22n

# include<iostream># include<cstdio># include<algorithm># include<queue># include<complex># include<stack># include<math.h># include<cstring>#include<map>#define ll long long#define pi acos(-1)#define MP make_pair#define X first#define Y secondusing namespace std;const int maxn = (1<<18);int n,cnt;map<string,int> ma;char ch1[20],ch2[20];int du[20];int vis[20][20];ll dp[maxn];ll dfs(int st){    if(dp[st]!=-1) return dp[st];    int tmpdu[20];    ll tmp=0;    for(int j=0;j<cnt;j++) tmpdu[j]=du[j];    for(int i=0;i<cnt;i++){//删点 减度        if(st&(1<<i)){            for(int j=0;j<cnt;j++) if(vis[i][j]){                tmpdu[j]--;            }        }    }    for(int j=0;j<cnt;j++) if(!(st&(1<<j))&&!tmpdu[j]){        tmp+=dfs(st|(1<<j));    }    return dp[st]=tmp;}int main(){    //freopen("a.txt","r",stdin);    while(scanf("%d",&n)!=EOF){        ma.clear(); cnt=0;        memset(du,0,sizeof(du));        memset(vis,0,sizeof(vis));        for(int i=1;i<=n;i++){            scanf("%s%s",ch1,ch2);            if(ma.find(string(ch1))==ma.end()) ma[string(ch1)]=cnt++;            if(ma.find(string(ch2))==ma.end()) ma[string(ch2)]=cnt++;            int u=ma[string(ch1)],v=ma[string(ch2)];            vis[u][v]=1;            du[v]++;        }        memset(dp,-1,sizeof(dp));        dp[(1<<cnt)-1]=1;        dfs(0);        printf("%lld\n",dp[0]);    }    return 0;}
0 0
原创粉丝点击