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入门的更多相关文章

  1. Hdu-1565 方格取数(1) (状态压缩dp入门题

    方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total S ...

  2. POJ3254Corn Fields(状态压缩DP入门)

    题目链接 题意:一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方格不能同时放牛,即牛与牛不能相邻.问有多少种放牛方案(一 ...

  3. 状态压缩DP入门题

    . /*本题为状态压缩题 题目大意 : 一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧, 可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方 格不能同时放牛(不包括斜着的 ...

  4. poj - 3254 Corn Fields (状态压缩dp入门)

    http://poj.org/problem?id=3254 参考:http://blog.csdn.net/accry/article/details/6607703 农夫想在m*n的土地上种玉米, ...

  5. 状态压缩dp 入门

    1.有一张n*m (n<=m)的棋盘,在上面放n个中国象棋里的车,使得任意两个车不能相互攻击,总共有多少种不同的方案. 2.有一张n*m (n<=m)的棋盘,其中有些格子里面不能放,在上面 ...

  6. POJ3254(入门状态压缩dp)

    Corn Fields Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 13203   Accepted: 6921 Desc ...

  7. 『最短Hamilton路径 状态压缩DP』

    状压DP入门 最短Hamilton路径 Description 给定一张 n(n≤20) 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径. Hamil ...

  8. poj 3311 floyd+dfs或状态压缩dp 两种方法

    Hie with the Pie Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 6436   Accepted: 3470 ...

  9. hoj2662 状态压缩dp

    Pieces Assignment My Tags   (Edit)   Source : zhouguyue   Time limit : 1 sec   Memory limit : 64 M S ...

随机推荐

  1. Delphi的String内存结构(够清楚) good

    变量s的内存结构为(字符串编码)A8 03 (字符宽度)01 00 (引用计数)FF FF FF FF (字符串长度)0A 00 00 00 (实际内容)31 32 33 34 35 36 37 38 ...

  2. Lucene.Net 2.3.1开发介绍 —— 三、索引(一)

    原文:Lucene.Net 2.3.1开发介绍 -- 三.索引(一) 在说索引之前,先说说索引是什么?为什么要索引?怎么索引? 先想想看,假如现在有一个文本,我们会怎么去搜索.比如,有一个string ...

  3. Swift - 使用UIWebView和UIToolbar制作一个浏览器

    使用网页控件(UIWebView)与工具栏控件(UIToolbar),我们可以自制一个小型的浏览器,其功能如下: 1,输入网址,点击“Go”按钮加载网页 2,加载过程中有进度条,同时可以点击停止按钮取 ...

  4. 用Swift开发二维码扫描器教程

    (原文:Building a QR Code Reader in Swift 作者:Simon Ng 译者:xiaoying )我相信大多数人都知道二维码(QR code)是什么,如果你对这个概念还不 ...

  5. Eclipse插件引入jar包的方法(转)

    搞了两天,终于找到解决办法了.原来  Eclipse 插件项目引入外面的jar包不能用   build path---->add external jars的方法. 先说明两个概念:类加载器,O ...

  6. IBinder在进程之间传递一个对象的形式(一)

    主张 什么时候service通常被称为远程时的,用到aidl来定一个接口供service和client来使用,这个事实上就是使用Binder机制的IPC通信.当client bind service成 ...

  7. JavaFX游戏开发效率浅谈

    声明:   本博客文章原创类别的均为个人原创,版权所有.转载请注明出处: http://blog.csdn.net/ml3947,另外本人的个人博客:http://www.wjfxgame.com. ...

  8. Delphi中类的运行期TypeInfo信息结构说明

    Delphi中类的运行期TypeInfo信息结构说明 CnPack 开源软件项目 2007-09-19 21:55:58 Delphi中类的运行期TypeInfo信息结构说明作者:刘啸CnPack开发 ...

  9. Delphi VMT的前世今生(研究一下D7的VMT表结构)

    主要是TObject那些虚函数,到底放在了哪里?

  10. 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 ...