状压dp学习笔记

来源:互联网 发布:spring 源码书籍推荐 编辑:程序博客网 时间:2024/06/04 21:15

最近才开始学习状压dp,以前就听听没写过。到目前为止,我对状压dp的应用就是用数位表示点,通过枚举不同的数,也就是不同的到达状态,来实现状态的转移。跟着网上的博客切题中

1.POJ3254 Corn Fields
http://poj.org/problem?id=3254

做的第一个状压题,基本是跟着网上的思路写的,状压dp真是很神奇,通过位运算能解决很多问题。

#include<cstdio>#include<cstring>using namespace std;int ok[1<<13], each[1<<13], cnt;bool check(int x){    return (x&(x<<1));}bool check2(int x, int y){    return (ok[x]&each[y]);}int main(){    int m, n, a, dp[13][1<<13];    while(~scanf("%d%d", &m, &n))    {        memset(dp, 0, sizeof(dp));        memset(each, 0, sizeof(each));        memset(ok, 0, sizeof(ok));        cnt=0;        for(int i=1; i<=m; i++)        {            for(int j=1; j<=n; j++)            {                scanf("%d", &a);                if(a==0)                {                     each[i]+=(1<<(j-1));                }            }      //      printf("each[%d]=%d\n", i, each[i]);        }        for(int i=0; i<(1<<n); i++)        {            if(!check(i))                ok[cnt++]=i;        }        for(int i=0; i<cnt; i++)        {            if(!check2(i, 1))            {                 dp[1][i]=1;            }        }        for(int i=2; i<=m; i++)        {            for(int j=0; j<cnt; j++)//第i行当前处于j种取值            {                if(check2(j, i))//如果第j种取值不符合规定                    continue;                for(int h=0; h<cnt; h++) //第i-1行当前处于h种取值                {                    if(check2(h, i-1))                        continue;                    if(!(ok[j]&ok[h]))                        dp[i][j]+=dp[i-1][h];                }            }        }        int ans=0;        for(int i=0; i<cnt; i++)        {            ans+=dp[m][i];            ans%=100000000;        }        printf("%d\n", ans);    }    return 0;}

2.hdu 3001 Travelling

http://acm.hdu.edu.cn/showproblem.php?pid=3001

因为是最多经过两次,所以用三进制表示,因为习惯了二进制表示,一开始写的很丑而且都调不出bug。除了三进制之外,思路其实差不多。

#include<cstdio>#include<cstring>#include<iostream>#include<cmath>#include<algorithm>using namespace std;#define INF 0x1f1f1f1fint dis[15][15];int index[15] ;int record[60000][15];int dp[60000][15];void init_record(){    for(int i=0; i<59050; i++)    {       int t = i;       for(int j = 1; j <= 10; ++j){           record[i][j] = t%3;           t /= 3;           if(t == 0)break;       }    }    index[0]=0;    index[1]=1;    for(int i=2; i<=11; i++)   {         index[i]=index[i-1]*3;   }}int main(){    int n, m, a, b, w;    init_record();    while(~scanf("%d%d", &n, &m))    {       memset(dis, INF, sizeof(dis));        for(int i=0; i<m; i++)        {            scanf("%d%d%d", &a, &b, &w);            if(w<dis[a][b])                dis[a][b]=dis[b][a]=w;        }        memset(dp, INF, sizeof(dp));        int ans=INF;        for(int state=1 ; state<index[n+1]; state++)        {            int flag=1;            for(int i=1; i<=n; i++)            {                if(record[state][i]==0)                {                    flag=0;continue;                }                if(state==index[i])                {                    dp[state][i]=0;                    continue;                }                for(int j=1; j<=n; j++)                {                    if(i==j) continue;                    if(record[state][j]==0||dis[j][i]==INF) continue;                    int newstate=state-index[i];                    dp[state][i]=min(dp[state][i], dp[newstate][j]+dis[j][i]);                }            }            if(flag)            {                for(int j=1; j<=n; j++)                    ans=min(ans, dp[state][j]);            }        }        if(ans==INF)            printf("-1\n");        else            printf("%d\n", ans);    }    return 0;}

。。。待续

原创粉丝点击