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. mysql update改动多条数据

    通常情况下,我们会使用下面SQL语句来更新字段值: 复制代码代码例如以下: UPDATE mytable SET myfield='value' WHERE other_field='other_va ...

  2. ExtJs4 笔记(6) Ext.MessageBox 消息对话框

    本篇演示消息对话框的用法,ExtJs封装了可能用到的各类消息框,并支持自定义的配置. 如下是用到的html: [html] <h1>各种消息框</h1> <div id= ...

  3. ExtJs4 笔记(3) Ext.Ajax 对ajax的支持

    本篇主要介绍一下ExtJs常用的几个对JS语法的扩展支持,包括Ajax封装,函数事件操作封装,还有扩展的常用函数等.Ajax服务端交互式操作是提交到.NET MVC.后续服务端交互都采用这一方式实现. ...

  4. [Android学习笔记]扩展application

    扩展Application对象 每一个应用程序启动之后,都会分配一个linux用户,并且运行在一个独立的进程中.默认情况下,一个应用程序只会运行在一个进程中(可以通过配置android:process ...

  5. c#Enum的用法

    public enum ResType { Role = 0, Dept = 1, Group = 2, Site = 3, Org = 4, Sub=8 } 这里定义了一个enum    ResTy ...

  6. My Emacs For Common Lisp

    My Emacs For Common Lisp My Emacs For Common Lisp

  7. linux下C语言socket网络编程简例

    原创文章,转载请注明转载字样和出处,谢谢! 这里给出在linux下的简单socket网络编程的实例,使用tcp协议进行通信,服务端进行监听,在收到client的连接后,发送数据给client:clie ...

  8. Apache+Django+Mysql环境配置

    环境要求:Apache:2.2  Mysql:5.5 Django:1.5 python:2.7 首先下载mod_wsgi-win32-ap22py27-3.3.so 下载下来后,改名成mod_wsg ...

  9. ThinkPHP多应用/项目配置技巧(使用同一配置文件)--(十六)

    原文:ThinkPHP多应用/项目配置技巧(使用同一配置文件)--(十六) ThinkPHP多应用配置技巧(没有使用分组,这是通过入口文件产生的Home.Admin)----很实用! 比如:现在有Ho ...

  10. 小侃#pragma

    #pragma是一个编译器指令. ================================================================ #pragma comment(li ...