博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
状态压缩DP
阅读量:5226 次
发布时间:2019-06-14

本文共 5665 字,大约阅读时间需要 18 分钟。

1:POJ 
炮兵阵地

  预先处理好情况,然后又类似格子取数的状压。

我们用DP[I][J][K]表示处理第I个格子,I-1格子的状态为J,I-2的格子为K,然后转移

 1 #include<stdio.h>
 2 #include<
string.h>
 3 #include<algorithm>
 4 #include<math.h>
 5 #include<vector>
 6 
using 
namespace std;
 7 
char s[
123][
123];
 8 
int n,m,dp[
123][
123][
123];
 9 
int ok[
12345],mp[
123][
123];
10 vector<
int>v[
123];
11 
int t;
12 
int cal(
int x)
//
计算能放的数量
13 {
14     
int ans=
0;
15     
while (x){
16         
if (x&
1) ans++;
17         x/=
2;
18     }
19     
return ans;
20 }
21 
22 
void init()
//
预处理
23 {
24     t=
0;
25     
for (
int i=
0;i<(
1<<m);i++)
26     {
27         
if ((i<<
1)&i) 
continue;
28         
if ((i<<
2)&i) 
continue;
29         ok[t++]=i;
30     }
31     
for (
int i=
0;i<n;i++)
32     {
33         v[i].clear();
34         
for (
int j=
0;j<t;j++)
35         {
36             
int flag=
1;
37             
int top=
0;
38             
for (
int k=
0;k<m;k++)
39                 
if (s[i][k]==
'
H
'&&(ok[j]&(
1<<k)))
40                 {
41                 flag=
0;
42                 
break;
43                 }
44             
if (flag) v[i].push_back(ok[j]);
45       }
46     }
47 }
48 
49 
int main()
50 {
51     
while (scanf(
"
%d%d
",&n,&m)!=EOF)
52     {
53         
for (
int i=
0;i<n;i++) scanf(
"
%s
",s[i]);
54         init();
55         memset(dp,-
1,
sizeof(dp));
56         
for (
int i=
0;i<v[
0].size();i++) dp[
0][i][
0]=cal(v[
0][i]);
//
处理1,2行的情况
57         
for (
int i=
0;i<v[
0].size();i++)
58             
for (
int j=
0;j<v[
1].size();j++)
59             
if (!(v[
0][i]&v[
1][j])&&dp[
0][i][
0]!=-
1)  dp[
1][j][i]=dp[
0][i][
0]+cal(v[
1][j]);
60 
61         
for (
int i=
2;i<n;i++)
62             
for (
int j=
0;j<v[i].size();j++)
63               
for (
int k=
0;k<v[i-
1].size();k++){
64                 
if (v[i][j]&v[i-
1][k]) 
continue;
65                   
for (
int p=
0;p<v[i-
2].size();p++)
66                     
if (dp[i-
1][k][p]!=-
1&&(v[i][j]&v[i-
2][p])==
0)
67                     dp[i][j][k]=max(dp[i][j][k],dp[i-
1][k][p]+cal(v[i][j]));
68            }
69         
int ans=
0;
70         
for (
int i=
0;i<t;i++)
71         
for (
int j=
0;j<t;j++)
72         ans=max(ans,dp[n-
1][i][j]);
73     printf(
"
%d\n
",ans);
74     }
75   
return 
0;
76 }

2:POJ 3254 

 

Corn Fields

 

 入门提: 1 #include<stdio.h>

 2 #include<
string.h>
 3 #include<math.h>
 4 #include<vector>
 5 #include<algorithm>
 6 
using 
namespace std;
 7 
int dp[
22][
1<<
13];
 8 
int mp[
20][
20];
 9 vector<
int> v[
2134];
10 
const 
int M=
100000000;
11 
int n,m;
12 
int t;
13 
int state[
123456];
14 
15 
void init()
16 {
17     t=
0;
18     
for (
int i=
0;i<n;i++)
19       
for (
int j=
0;j<m;j++) scanf(
"
%d
",&mp[i][j]);
20     
for (
int i=
0;i<(
1<<m);i++)
21     {
22         
if (i&(i>>
1)) 
continue;
23         
if (i&(i<<
1)) 
continue;
24         state[++t]=i;
25         }
26     
for (
int i=
0;i<n;i++)
27     {
28         v[i].clear();
29         
for (
int j=
1;j<=t;j++){
30              
int flag=
1;
31         
for (
int p=
0;p<m;p++)
32         
if (mp[i][p]==
0&&(state[j]&(
1<<p)))
33         {
34             flag=
0;
35             
break;
36         }
37         
if (flag) v[i].push_back(state[j]);
38       }
39     }
40 }
41 
42 
int main()
43 {
44     
while (scanf(
"
%d%d
",&n,&m)!=EOF)
45     {
46          init();
47          memset(dp,
0,
sizeof(dp));
48          
for (
int i=
0;i<v[
0].size();i++) dp[
0][i]=
1;
49          
for (
int i=
1;i<n;i++)
50          
for (
int j=
0;j<v[i].size();j++){
51                 
int now=v[i][j];
52                 
for (
int k=
0;k<v[i-
1].size();k++)
53                 
if (!(now&(v[i-
1][k])))
54                    {dp[i][j]+=dp[i-
1][k];
55                              dp[i][j]%=M;
56                           }
57     }
58     
int ans=
0;
59     
for (
int i=
0;i<v[n-
1].size();i++){
60         ans+=dp[n-
1][i];
61         ans%=M;
62     }
63     printf(
"
%d\n
",ans);
64   }
65   
return 
0;
66 }        
                                                                                                                                                         
POJ:3311
哈密顿回路:N只有10,先求出任意一点的回路,难后状态压缩:
#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define inf 123456789int n;int mp[12][12],dp[1<<12][12];using namespace std;int main(){ while (scanf("%d",&n)!=EOF) { if (n==0) break; for (int i=0;i<=n;i++) for (int j=0;j<=n;j++) scanf("%d",&mp[i][j]); for (int k=0;k<=n;k++) for (int i=0;i<=n;i++) for (int j=0;j<=n;j++) if (mp[i][j]>mp[i][k]+mp[k][j]) mp[i][j]=mp[i][k]+mp[k][j]; for (int i=0;i<(1<
#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define inf 123456789int n;int mp[12][12],dp[1<<12][12];int a[12];using namespace std;int main(){ while (scanf("%d",&n)!=EOF) { if (n==0) break; for (int i=0;i<=n;i++) for (int j=0;j<=n;j++) scanf("%d",&mp[i][j]); for (int k=0;k<=n;k++) for (int i=0;i<=n;i++) for (int j=0;j<=n;j++) if (mp[i][j]>mp[i][k]+mp[k][j]) mp[i][j]=mp[i][k]+mp[k][j]; int ans=inf; for (int i=1;i<=n;i++) a[i]=i; do { int k=0; int t=0; for (int i=1;i<=n;i++) k+=mp[t][a[i]],t=a[i]; k+=mp[t][0]; ans=min(ans,k); }while (next_permutation(a+1,a+n+1)); printf("%d\n",ans); } return 0;}

hdu 3001:

一辈子看错题:注意一个城市可以走两次

还有重边。

三进制表示很神奇

1 #include 
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #define inf 0x3f3f3f3f12 typedef long long ll;13 using namespace std;14 int state[12];15 int vis[123456][12];16 int dp[123456][13];17 int mp[13][13];18 int n,m;19 void init()20 {21 state[0]=1;22 for (int i=1;i<=10;i++)23 state[i]=state[i-1]*3;24 for (int i=0;i<=state[10];i++)25 {26 int tmp=i;27 for (int j=0;j<=10;j++){28 vis[i][j]=tmp%3;29 tmp/=3;30 }31 }32 }33 34 int main()35 {36 init();37 while (scanf("%d%d",&n,&m)!=EOF)38 {39 memset(dp,inf,sizeof(dp));40 memset(mp,inf,sizeof(mp));41 for (int i=0;i
=2||mp[j][k]==inf) continue;59 dp[i+state[k]][k]=min(dp[i+state[k]][k],dp[i][j]+mp[j][k]);60 }61 }62 if (flag)63 for (int j=0;j
View Code

 

  

POJ2411;
 求N*M能放多少1*2的格子,虽然可以用二进制表示,但是转移方程状态又是另外一种写法
参考:http://blog.csdn.net/shiwei408/article/details/8821853
     http://www.2cto.com/kf/201208/146894.html
这里解释了转移方程的写法。

转载于:https://www.cnblogs.com/forgot93/p/3869304.html

你可能感兴趣的文章
第16周总结
查看>>
C#编程时应注意的性能处理
查看>>
Fragment
查看>>
比较安全的获取站点更目录
查看>>
苹果开发者账号那些事儿(二)
查看>>
使用C#交互快速生成代码!
查看>>
UVA11374 Airport Express
查看>>
P1373 小a和uim之大逃离 四维dp,维护差值
查看>>
NOIP2015 运输计划 树上差分+树剖
查看>>
P3950 部落冲突 树链剖分
查看>>
读书_2019年
查看>>
读书汇总贴
查看>>
微信小程序 movable-view组件应用:可拖动悬浮框_返回首页
查看>>
MPT树详解
查看>>
空间分析开源库GEOS
查看>>
RQNOJ八月赛
查看>>
前端各种mate积累
查看>>
jQuery 1.7 发布了
查看>>
Python(软件目录结构规范)
查看>>
Windows多线程入门のCreateThread与_beginthreadex本质区别(转)
查看>>