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. jsp中将后台传递过来的json格式的list数据绑定到下拉菜单select

    <span style="white-space:pre"> </span> <select><c:forEach var="f ...

  2. ADO异步查询显示进度条

    一般,ADO都是以同步的方式来处理数据.这就是说,当ADO开始处理数据后,应用程序必须等到ADO处理完毕之后才可以继续执行.但是除了同步执行方式之外,ADO也提供了异步执行的方式,允许当ADO处理时, ...

  3. Python语法

  4. java matlab混合编程之返回值Struct类型

    java matlab混合编程的时候当返回值是Struct类型(matlab中的返回类型)如何来取得(java中)其值? 上网找,看到这个网页:http://www.mathworks.cn/cn/h ...

  5. Zero Clipboard - 跨浏览器兼容的“复制到剪贴板”功能

    开发中经常会用到复制的功能,在 IE 下实现比较简单,但要想做到跨浏览器比较困难了. 本文将介绍一个跨浏览器的库类 Zero Clipboard ,它利用 Flash 进行复制,所以只要浏览器装有 F ...

  6. 我经历的IT公司面试及离职感受(转)

    毕业后几年一直待在广州,觉得这是一个比较生活化及务实的城市,其互联网公司和相应的投融资环境都不如北深上活跃,大大小小的面试也有几十个,有点规模的公司应该都面试过了,面试一般会见到主力技术人员,技术主管 ...

  7. XML实例文档

    from: http://www.w3school.com.cn/xpath/xpath_examples.asp XML实例文档 我们将在下面的例子中使用这个 XML 文档: "books ...

  8. jQuery EasyUI API 中文文档 - 布局(Layout)

    <html> <head> <script src="jquery-easyui/jquery.min.js"></script> ...

  9. java常见的输入和输出流案例研究(一个)

    字节输入和输出流 1.FileInputStream[文件字节输入流]->读取文件内容 用途:从文件系统中的文件获得输入字节.经常使用于读取图像.声音等原始字节流,读取字符流可考虑使用FileR ...

  10. UVa 213 Message Decoding(World Finals1991,串)

     Message Decoding  Some message encoding schemes require that an encoded message be sent in two part ...