状态压缩dp入门
poj1321 http://poj.org/problem?id=1321
我们可以把棋盘的每一行看做是一个状态,如果某一列放置了棋子,那么就标记为1,否则就标记为0.然后把它看成是一个二进制数,然后转为10进制数,就可以当做数组下标然后进行状态转移了
设dp[i][s] 为处理到第i行时,状态为s的方法数
那么我们枚举第i-1行的所有状态s
dp[i][s] += dp[i-1][s]; //表示第i行不放置棋子的方法数
dp[i][s|(1<<j)] += dp[i-1][s] //表示第i行第j列放置棋子的方法数 (前提是 chess[i][j]=='#' && 状态s第j列没有放过棋子)
#include <stdio.h>
#include <string.h>
char chess[][];int dp[][<<];
int n,k;
int main()
{
int i,j,s,ss;
while(scanf("%d%d",&n,&k)!=EOF)
{
int ans = ;
if(n==-) return ;
memset(dp,,sizeof(dp));
for(i=; i<=n; ++i)
{
scanf("%s",chess[i]);
}
dp[][] = ;
for(i=; i<=n; ++i)
for(s=; s<(<<n); ++s)
{ for(j=; j<n; ++j)
if(chess[i][j]=='#'&&((<<j)&s)==)
dp[i][s|<<j] += dp[i-][s];//表示第i行第j列放置棋子的方法数
dp[i][s] += dp[i-][s]; //表示第i行不放置棋子的方法数
}
///for(j=1; j<=n; ++j)
for(s=0; s<(1<<n); ++s)
{
i = s;
int cnt = ;
for(;i;i-= i&-i)//统计状态s有多少个1,表示放了多少个棋子
cnt ++;
if(cnt==k)
ans+= dp[n][s];
}
printf("%d\n",ans);
}
return ;
}
poj3254 http://poj.org/problem?id=3254
本来这一题也想用上面那题的思路做,可是后来发现不行,因为上面那题一行只选择一个位置,而这题一行可以选择多个位置。
那么我们这题可以枚举多个位置,如果和上一行的状态不冲突,那么上一行的状态就能转移到这一行
#include <stdio.h>
#include <string.h> int field[];
int situation[];
int dp[][<<];
const int MOD = ;
bool isOk(int s)
{
if(s&(s>>)) return false;
return true;
} int main()
{
int n,m,i,j,s,ss,cnt,ans;
while(scanf("%d%d",&n,&m)!=EOF)
{
ans = cnt = ;
memset(dp,,sizeof(dp));
memset(field,,sizeof(field));
for(s=; s<(<<m); ++s) if(isOk(s)) situation[cnt++] = s;//记录所有可行的状态,即不能有相邻的1
for(i=; i<n; ++i)
for(j=; j<m; ++j)
{
scanf("%d",&s);
field[i] |= (!s)<<j;//这里这样存的含义是,如果situation[] & field[] 不为0,说明状态situation不行
} //dp[i][j] 表示处理完前i行,第j个状态的方法数
for(i=; i<cnt; ++i)
if( !(situation[i] & field[]))
dp[][i] = ; for(i=; i<n; ++i)
for(s=; s<cnt; ++s)
{
if(situation[s]&field[i]) continue;//这一行的状态要合法
for(ss=; ss<cnt; ++ss)
{
if(situation[ss] & situation[s]) continue;//这一行的状态和上一行的状态不合法
dp[i][s] += dp[i-][ss];//只要上一行的状态ss和这一行的状态s不冲突,那么就能转化为状态s
dp[i][s] %= MOD;
}
}
for(i=; i<cnt; ++i)
ans = (ans + dp[n-][i]) % MOD;
printf("%d\n",ans); }
return ;
}
poj1185 http://poj.org/problem?id=1185
和上面那题差不多,只是当前行的状态不止和上一行有关,还和上上一行有关,所以数组要多开一维
奇怪的是为什么用scanf("%c");G++ac,C++wa 用scanf("%s")G++和C++都wa
/*
分析:一行的状态不能有 11(连续的两个1) 也能有101(隔一个空然后出现一个1)
dp[i][j][k] 表示第i行状态为j第i-1行状态为k时,最多有多少个炮兵摆放
dp[i][j][k] = max(dp[i][j][k],dp[i-1][k][t]+num[j]);
*/ #include <stdio.h>
#include <string.h>
int situation[];
char matrix[][];
int map[];
int num[];
int dp[][][];
bool isOk(int s)
{
if(s&(s<<)) return false;
if(s&(s<<)) return false;
return true;
} int count(int s)
{
int ret = ;
for(;s; s-= (s&-s))//统计状态s有多少个1
ret++;
return ret;
}
inline int max(const int &a, const int &b)
{
return a < b ? b : a;
}
int main()
{
int n,m,i,j,k,s,cnt,ans,t;
char ch;
while(scanf("%d%d",&n,&m)!=EOF)
{
cnt = ans = ;
memset(dp,-,sizeof(dp));
for(s=; s<(<<m); ++s) if(isOk(s))
{
num[cnt] = count(s);
situation[cnt++] = s;
} for(i=; i<n; ++i)
{ getchar();
map[i] = ;
for(j=; j<m; ++j)
{
scanf("%c",&ch);
if(ch=='H') map[i] |= <<j;
}
}
for(i=; i<cnt; ++i)
if(!(situation[i] & map[]))
dp[][i][] = num[i];
for(i=; i<n; ++i)
for(j=; j<cnt; ++j)
{
if(situation[j] & map[i]) continue;
for(k=; k<cnt; ++k)
{
if(situation[j] & situation[k]) continue;
for(t= ;t<cnt; ++t)
{
if(situation[j] & situation[t]) continue;
if(dp[i-][k][t]==-) continue;
dp[i][j][k] = max(dp[i][j][k],dp[i-][k][t] + num[j]);
}
}
}
for(i=; i<n; ++i)
for(j=; j<cnt; ++j)
for(k=; k<cnt; ++k)
ans = max(ans,dp[i][j][k]);
printf("%d\n",ans);
} return ;
}
hdu3001 http://acm.hdu.edu.cn/showproblem.php?pid=3001
平常的状态压缩,都是某个位置放(1)或者不放(0),所以可以直接用二进制进行压缩
但是这题,每个点可以走两次,那么就可以标记为0,1,2 所以要用三进制进行压缩。
即用一个数组存储每个状态的三进制的每位
#include <stdio.h>
#include <string.h>
const int INF = <<;
int three[],situation[][],edge[][],dp[][];
void init()
{
int i,t,cnt;
three[] = ;
for(i=; i<=; ++i)
three[i] = three[i-] * ;
for(i=; i<; ++i)
{
t = i;
cnt = ;
while(t)//存储状态的三进制的每一位
{
situation[i][cnt++] = t % ;
t /= ;
}
}
}
inline int min(const int &a, const int &b)
{
return a < b ? a : b;
}
int main()
{
init();
int n,m,i,j,a,b,c,ans,s;
while(scanf("%d%d",&n,&m)!=EOF)
{ for(i=; i<n; ++i)
for(j=; j<n; ++j)
edge[i][j] = INF;
for(i=; i<n; ++i)
for(s=; s<three[n]; ++s)
dp[s][i] = INF;
ans = INF;
for(i=; i<m; ++i)
{
scanf("%d%d%d",&a,&b,&c);
a--,b--;
if(edge[a][b] > c)
edge[a][b] = edge[b][a] = c;
}
for(i=; i<n; ++i) dp[three[i]][i] = ;//处于源点的距离为0
//因为走过某些城市可以是任意组合的,所以枚举这些状态
for(s=; s<three[n]; ++s)
{
bool flag = true;
for(i=; i<n; ++i)
{
if(situation[s][i]==) flag = false;//状态s的第i位为0,说明没有走过所有的城市
if(dp[s][i]==INF) continue;
for(j=; j<n; ++j)
{
if(i==j) continue;
if(edge[i][j]==INF || situation[s][j]==) continue;
int nextS = s + three[j];
dp[nextS][j] = min(dp[nextS][j],dp[s][i] + edge[i][j]);
}
}
if(flag)//走过所有的状态
{
for(i=; i<n; ++i)
ans = min(ans,dp[s][i]);
}
}
if(ans == INF)
printf("-1\n");
else
printf("%d\n",ans);
}
return ;
}
状态压缩dp入门的更多相关文章
- Hdu-1565 方格取数(1) (状态压缩dp入门题
方格取数(1) Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total S ...
- POJ3254Corn Fields(状态压缩DP入门)
题目链接 题意:一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方格不能同时放牛,即牛与牛不能相邻.问有多少种放牛方案(一 ...
- 状态压缩DP入门题
. /*本题为状态压缩题 题目大意 : 一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧, 可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方 格不能同时放牛(不包括斜着的 ...
- poj - 3254 Corn Fields (状态压缩dp入门)
http://poj.org/problem?id=3254 参考:http://blog.csdn.net/accry/article/details/6607703 农夫想在m*n的土地上种玉米, ...
- 状态压缩dp 入门
1.有一张n*m (n<=m)的棋盘,在上面放n个中国象棋里的车,使得任意两个车不能相互攻击,总共有多少种不同的方案. 2.有一张n*m (n<=m)的棋盘,其中有些格子里面不能放,在上面 ...
- POJ3254(入门状态压缩dp)
Corn Fields Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 13203 Accepted: 6921 Desc ...
- 『最短Hamilton路径 状态压缩DP』
状压DP入门 最短Hamilton路径 Description 给定一张 n(n≤20) 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径. Hamil ...
- poj 3311 floyd+dfs或状态压缩dp 两种方法
Hie with the Pie Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 6436 Accepted: 3470 ...
- hoj2662 状态压缩dp
Pieces Assignment My Tags (Edit) Source : zhouguyue Time limit : 1 sec Memory limit : 64 M S ...
随机推荐
- STL之涉及到的算法
一.非变异算法 是一组不破坏操作数据的模板函数,用来对序列数据进行逐个处理.元素查找.子序列搜索.统计和匹配.非变异算法具有极为广泛的适用性,基本上可应用与各种容器. 1查找容器元素find 它用于查 ...
- 手把手教你_android自己主动化实践方案选型
接到一个android自己主动化的任务,看了看手中的家伙:ranorex,appium,uiautomator 当然先捡商用的试试,简单呀,能够录制回放,只是不是抱特别大的期望,这个爷比較娇气,要是a ...
- Objective-C中经常使用的结构体NSRange,NSPoint,NSSize(CGSize),NSRect
Objective-C中经常使用的结构体NSRange,NSPoint,NSSize(CGSize),NSRect 1 NSRange NSRange 的原型为 typedef struct _N ...
- table显示边框问题,隐藏行线,列线
只显示上边框 <table frame=above> 只显示下边框 <table frame=below> 只显示左.右边框 <table frame=vsides> ...
- JavaScript实战
JavaScript之单例实战 一.概述 所谓单例模式,顾名思义即一个类只有一个实例. 所以,当我们创建一个实例时,就必须判断其是否已经存在了这个实例,如果已经存在了这个实例,那么就返回这个已经存在的 ...
- OCP读书笔记(10) - 使用闪回技术I
使用闪回技术查询数据 闪回查询:就是查询表在过去某个时间点的数据,所用到的技术就是undo数据 SQL> conn scott/tiger 创建测试表 SQL> create table ...
- XHTML学习笔记
1.每个网页都是在XML声明和DTD之后以一个<html>标记开始,以一个</html>标记结束 这两个标记表明在它们之间的所有文本都是HTML格式,他告诉浏览器如何理解该文档 ...
- 每日算法之三十八:Anagrams
Given an array of strings, return all groups of strings that are anagrams. Note: All inputs will be ...
- ARMv8 Linux内核异常处理过程分析
NOTE:为了方便大家阅读,制作了PDF版文档.下载请猛戳这里 老样子,为了赚点积分下载其它人的文件,下载以上资料须要资源分2分. 假设没有积分请留言全部文档,留下邮箱就可以. 看了Linaro提供的 ...
- Learning Cocos2d-x for WP8(7)——让Sprite动起来
原文:Learning Cocos2d-x for WP8(7)--让Sprite动起来 C#(wp7)兄弟篇Learning Cocos2d-x for XNA(7)——让Sprite动起来 本讲将 ...