状态压缩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 ...
随机推荐
- Delphi的String内存结构(够清楚) good
变量s的内存结构为(字符串编码)A8 03 (字符宽度)01 00 (引用计数)FF FF FF FF (字符串长度)0A 00 00 00 (实际内容)31 32 33 34 35 36 37 38 ...
- Lucene.Net 2.3.1开发介绍 —— 三、索引(一)
原文:Lucene.Net 2.3.1开发介绍 -- 三.索引(一) 在说索引之前,先说说索引是什么?为什么要索引?怎么索引? 先想想看,假如现在有一个文本,我们会怎么去搜索.比如,有一个string ...
- Swift - 使用UIWebView和UIToolbar制作一个浏览器
使用网页控件(UIWebView)与工具栏控件(UIToolbar),我们可以自制一个小型的浏览器,其功能如下: 1,输入网址,点击“Go”按钮加载网页 2,加载过程中有进度条,同时可以点击停止按钮取 ...
- 用Swift开发二维码扫描器教程
(原文:Building a QR Code Reader in Swift 作者:Simon Ng 译者:xiaoying )我相信大多数人都知道二维码(QR code)是什么,如果你对这个概念还不 ...
- Eclipse插件引入jar包的方法(转)
搞了两天,终于找到解决办法了.原来 Eclipse 插件项目引入外面的jar包不能用 build path---->add external jars的方法. 先说明两个概念:类加载器,O ...
- IBinder在进程之间传递一个对象的形式(一)
主张 什么时候service通常被称为远程时的,用到aidl来定一个接口供service和client来使用,这个事实上就是使用Binder机制的IPC通信.当client bind service成 ...
- JavaFX游戏开发效率浅谈
声明: 本博客文章原创类别的均为个人原创,版权所有.转载请注明出处: http://blog.csdn.net/ml3947,另外本人的个人博客:http://www.wjfxgame.com. ...
- Delphi中类的运行期TypeInfo信息结构说明
Delphi中类的运行期TypeInfo信息结构说明 CnPack 开源软件项目 2007-09-19 21:55:58 Delphi中类的运行期TypeInfo信息结构说明作者:刘啸CnPack开发 ...
- Delphi VMT的前世今生(研究一下D7的VMT表结构)
主要是TObject那些虚函数,到底放在了哪里?
- activity_main.xml: java.lang.NullPointerException
1.错误描写叙述 eclipse.buildId=4.4.0.I20140606-1215 java.version=1.7.0_67 java.vendor=Oracle Corporation B ...