状态压缩DP(大佬写的很好,转来看)
奉上大佬博客 https://blog.csdn.net/accry/article/details/6607703
动态规划本来就很抽象,状态的设定和状态的转移都不好把握,而状态压缩的动态规划解决的就是那种状态很多,不容易用一般的方法表示的动态规划问题,这个就更加的难于把握了。难点在于以下几个方面:状态怎么压缩?压缩后怎么表示?怎么转移?是否具有最优子结构?是否满足后效性?涉及到一些位运算的操作,虽然比较抽象,但本质还是动态规划。找准动态规划几个方面的问题,深刻理解动态规划的原理,开动脑筋思考问题。这才是掌握动态规划的关键。
动态规划最关键的要处理的问题就是位运算的操作,容易出错,状态的设计也直接决定了程序的效率,或者代码长短。状态转移方程一定要仔细推敲,不可一带而过,要思考为什么这么做,掌握一个套路,遇见这类问题能快速的识别出问题的本质,找出状态转移方程和DP的边界条件。
下面是一些关于状态压缩DP的题目,大都不难。状压DP的东西还有很多,还会接着总结。
【POJ3254】Corn Fields
【题目大意】一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方格不能同时放牛,即牛与牛不能相邻。问有多少种放牛方案(一头牛都不放也是一种方案)
【解析】根据题意,把每一行的状态用二进制的数表示,0代表不在这块放牛,1表示在这一块放牛。首先很容易看到,每一行的状态要符合牧场的硬件条件,即牛必须放在能放牧的方格上。这样就能排除一些状态。另外,牛与牛之间不能相邻,这样就要求每一行中不能存在两个相邻的1,这样也能排除很多状态。然后就是根据上一行的状态转移到当前行的状态的问题了。必须符合不能有两个1在同一列(两只牛也不能竖着相邻)的条件。这样也能去掉一些状态。然后,上一行的所有符合条件的状态的总的方案数就是当前行该状态的方案数。
【状态表示】dp[state][i]:在状态为state时,到第i行符合条件的可以放牛的方案数
【状态转移方程】dp[state][i] =Sigma dp[state’][i-1] (state’为符合条件的所有状态)
【DP边界条件】首行放牛的方案数dp[state][1] =1(state符合条件) OR 0 (state不符合条件)
【代码】
#include <cstdio>
#include <cstring>
using namespace std;
#define mod 100000000
int M,N,top = 0;
int state[600],num[110];
int dp[20][600];
int cur[20];
inline bool ok(int x){
if(x&x<<1)return 0;
return 1;
}
void init(){
top = 0;
int total = 1 << N;
for(int i = 0; i < total; ++i){
if(ok(i))state[++top] = i;
}
}
inline bool fit(int x,int k){
if(x&cur[k])return 0;
return 1;
}
inline int jcount(int x)
{
int cnt=0;
while(x)
{
cnt++;
x&=(x-1);
}
return cnt;
}
int main(){
while(scanf("%d%d",&M,&N)!= EOF){
init();
memset(dp,0,sizeof(dp));
for(int i = 1; i <= M; ++i){
cur[i] = 0;
int num;
for(int j = 1; j <= N; ++j){
scanf("%d",&num);
if(num == 0)cur[i] +=(1<<(N-j));
}
}
for(int i = 1;i <= top;i++){
if(fit(state[i],1)){
dp[1][i] = 1;
}
}
for(int i = 2; i <= M; ++i){
for(int k = 1; k <= top; ++k){
if(!fit(state[k],i))continue;
for(int j = 1; j <= top ;++j){
if(!fit(state[j],i-1))continue;
if(state[k]&state[j])continue;
dp[i][k] = (dp[i][k] +dp[i-1][j])%mod;
}
}
}
int ans = 0;
for(int i = 1; i <= top; ++i){
ans = (ans + dp[M][i])%mod;
}
printf("%d\n",ans);
}
}
【POJ1185】炮兵阵地–经典状压DP
【题目大意】类似于上面一道题,一个方格组成的矩阵,每个方格可以放大炮用0表示,不可以放大炮用1表示(原题用字母),让放最多的大炮,大炮与大炮间不会互相攻击。
【解析】可以发现,对于每一行放大炮的状态,只与它上面一行和上上一行的状态有关,每一行用状态压缩的表示方法,0表示不放大炮,1表示放大炮,同样的,先要满足硬件条件,即有的地方不能放大炮,然后就是每一行中不能有两个1的距离小于2(保证横着不互相攻击),这些要预先处理一下。然后就是状态表示和转移的问题了,因为是和前两行的状态有关,所以要开个三维的数组来表示状态,当前行的状态可由前两行的状态转移而来。即如果当前行的状态符合前两行的约束条件(不和前两行的大炮互相攻击),则当前行的最大值就是上一个状态的值加上当前状态中1的个数(当前行放大炮的个数)
【状态表示】dp[i][j][k] 表示第i行状态为k,第i-1状态为j时的最大炮兵个数。
【状态转移方程】dp[i][k][t] =max(dp[i][k][t],dp[i-1][j][k]+num[t]); num[t]为t状态中1的个数
【DP边界条件】dp[1][1][i] =num[i] 状态i能够满足第一行的硬件条件(注意:这里的i指的是第i个状态,不是一个二进制数,开一个数组保存二进制状态)
【代码】
#include <cstdio>
#include <cstring>
using namespace std;
#define max(a,b) (a) > (b) ? (a) : (b)
int N,M;
char map[110][20],num[110],top;
int stk[70],cur[110];
int dp[110][70][70];
inline bool ok(int x){ //判断该状态是否合法,即不存在相邻的1之间的距离小于3的
if(x&(x<<1)) return 0;
if(x&(x<<2)) return 0;
return 1;
}
//找到所有可能的合法状态,最多60种
inline void jinit()
{
top=0;
int i,total=1<<N;
for(i=0;i<total;i++) if(ok(i)) stk[++top]=i;
}
//判断状态x是否与第k行匹配
inline bool fit(int x,int k)
{
if(cur[k]&x) return 0;
return 1;
}
//数一个整型数x的二进制中1的个数(用于初始化)
inline int jcount(int x)
{
int cnt=0;
while(x)
{
cnt++;
x&=(x-1);
}
return cnt;
}
int main(){
while(scanf("%d%d",&M,&N) != EOF){
if(N == 0 && M == 0)break;
jinit();
for(int i = 1; i <= M; ++i)scanf("%s",map[i]+1);
for(int i = 1; i <= M; ++i)
for(int j = 1; j <= N; ++j){
cur[i]=0;
for(j=1;j<=N;j++){
if(map[i][j]=='H')cur[i]+=(1<<(j-1));
}
}
memset(dp,-1,sizeof(dp));
//初始化第一行状态
for(int i = 1;i <= top;i++){
num[i]=jcount(stk[i]);
if(fit(stk[i],1))
dp[1][1][i]=num[i];
}
int i,t,j,k;
for(i = 2;i <= M;i++){
for(t = 1;t <= top;t++){
if(!fit(stk[t],i)) continue;
for(j = 1;j <= top;j++)
{
if(stk[t]&stk[j])continue;
for(k = 1;k <= top;k++)
{
if(stk[t]&stk[k])continue;
if(dp[i-1][j][k]==-1)continue;
dp[i][k][t] =max(dp[i][k][t],dp[i-1][j][k]+num[t]);
}
}
}
}
int ans = 0;
for(i = 1; i <= M; ++i)
for(j = 1; j <= top; ++j)
for(k = 1; k <= top; ++k)
ans = max(ans,dp[i][j][k]);
printf("%d\n",ans);
}
return 0;
}
【POJ3311】Hie With The Pie
【题目大意】类似于TSP问题,只是每个点可以走多次,比经典TSP问题不同的是要先用弗洛伊的预处理一下两两之间的距离。求最短距离。
【解析】可以用全排列做,求出一个最短的距离即可。或者用状态压缩DP.用一个二进制数表示城市是否走过
【状态表示】dp[state][i]表示到达i点状态为state的最短距离
【状态转移方程】dp[state][i] =min{dp[state][i],dp[state’][j]+dis[j][i]} dis[j][i]为j到i的最短距离
【DP边界条件】dp[state][i] =dis[0][i] state是只经过i的状态
【代码】
#include<iostream>
#define INF 100000000
using namespace std;
int dis[12][12];
int dp[1<<11][12];
int n,ans,_min;
int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%d",&n) && n)
{
for(int i = 0;i <= n;++i)
for(int j = 0;j <= n;++j)
scanf("%d",&dis[i][j]);
for(int k = 0;k <= n;++k)
for(int i = 0;i <= n;++i)
for(int j = 0;j <=n;++j)
if(dis[i][k] + dis[k][j]< dis[i][j])
dis[i][j] = dis[i][k] +dis[k][j];
for(int S = 0;S <= (1<<n)-1;++S)//枚举所有状态,用位运算表示
for(int i = 1;i <= n;++i)
{
if(S & (1<<(i-1)))//状态S中已经过城市i
{
if(S ==(1<<(i-1))) dp[S][i] =dis[0][i];//状态S只经过城市I,最优解自然是从0出发到i的dis,这也是DP的边界
else//如果S有经过多个城市
{
dp[S][i] = INF;
for(int j = 1;j <=n;++j)
{
if(S &(1<<(j-1)) && j != i)//枚举不是城市I的其他城市
dp[S][i] =min(dp[S^(1<<(i-1))][j] + dis[j][i],dp[S][i]);
//在没经过城市I的状态中,寻找合适的中间点J使得距离更短
}
}
}
}
ans = dp[(1<<n)-1][1] + dis[1][0];
for(int i = 2;i <= n;++i)
if(dp[(1<<n)-1][i] + dis[i][0] < ans)
ans = dp[(1<<n)-1][i] +dis[i][0];
printf("%d\n",ans);
}
return 0;
}
【HDU3001】Traveling
【题目大意】10个点的TSP问题,但是要求每个点最多走两边,不是只可以走一次,所以要用三进制的状态压缩解决这个问题。可以预处理每个状态的第k位是什么。
【解析】和tsp问题相同,类似于上面那个题
【状态表示】【状态转移方程】同上题,具体见代码
【代码】
#include <cstdio>
#include <cstring>
#define INF 0x1f1f1f1f //刚发现这里写0x1f1f1f跑的比0x1f1f1f1f差不多慢了一倍!Orz~
#define min(a,b) (a) < (b) ? (a) : (b)
using namespace std;
int N,M;
int tri[12] ={0,1,3,9,27,81,243,729,2187,6561,19683,59049};
int dig[59050][11]; //dig[state][k_dig] 状态state的第k位是多少
int edge[11][11],dp[59050][11];
int main(){
for(int i = 0; i < 59050; ++i){
int t = i;
for(int j = 1; j <= 10; ++j){
dig[i][j] = t%3;
t /= 3;
if(t == 0)break;
}
}
while(scanf("%d%d",&N,&M) != EOF){
memset(edge,INF,sizeof(edge));
int a,b,c;
while(M --){
scanf("%d%d%d",&a,&b,&c);
if(c < edge[a][b])edge[a][b] = edge[b][a] = c;
}
memset(dp,INF,sizeof(dp));
for(int i = 1; i <= N; ++i)dp[tri[i]][i] = 0;
int ans = INF;
for(int S = 0; S < tri[N+1]; ++S){
int visit_all = 1;
for(int i = 1; i <= N; ++i){
if(dig[S][i] == 0)visit_all = 0;
if(dp[S][i] == INF)continue;
for(int j = 1; j <= N; ++j){
if(i == j)continue;
if(edge[i][j] == INF ||dig[S][j] >= 2)continue;
int newS = S + tri[j];
dp[newS][j] =min(dp[newS][j],dp[S][i] + edge[i][j]);
}
}
if(visit_all){
for(int j = 1; j <= N; ++j)
ans = min(ans,dp[S][j]);
}
}
if(ans == INF){
puts("-1");
continue;
}
printf("%d\n",ans);
}
return 0;
}
【POJ2288】Islands and Bridge
【题目大意】求汉密尔顿的一道变形问题,中间每个点有权值,关于最后得分的描述如下
Suppose there are n islands. The value of aHamilton path C1C2…Cn is calculated as the sum of three parts. Let Vi be thevalue for the island Ci. As the first part, we sum over all the Vi values foreach island in the path. For the second part, for each edge CiCi+1 in the path,we add the product ViVi+1. And for the third part, whenever three consecutiveislands CiCi+1Ci+2 in the path forms a triangle in the map, i.e. there is abridge between Ci and Ci+2, we add the product ViVi+1*Vi+2.
这题要求让得分最高
【解析】发现每个点的状态由前面两个点确定,用DP(S,A,B)表示状态为S时,当前到达A,而上一个点是B时的最大得分,这个状态由DP(S’,B,C)通过从B走到A得到,S’=S-(1<<A),即S’状态就是经过B和C但不经过A的一个状态,C是不同于A和B的一个点。
【状态转移】dp[S][A][B] =max(dp[S][A][B],dp[S’][B][C]+temp) 这里的temp指的是加上的得分即VbVa+Va,如果构成三角关系(即A和C间有边),temp就要再加上VbVa*Vc.
【边界条件】DP((1<<A)+(1<<B),A,B)=Va+Vb+Va*Vb(A和B间有边)表示
【代码】
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 13;
const int MAX_S = 1<<(MAXN+1);
long long dp[MAX_S][MAXN+1][MAXN+1];
long long way[MAX_S][MAXN+1][MAXN+1];
int edge[MAXN+1][MAXN+1];
long long V[MAXN+1];
int N,M;
int main(){
int cas;
scanf("%d",&cas);
while(cas --){
memset(edge,0,sizeof(edge));
scanf("%d%d",&N,&M);
for(int i = 1; i <= N; ++i)
scanf("%d",&V[i]);
if(N == 1){
printf("%d 1\n",V[1]);
continue;
}
int a,b;
while(M --){
scanf("%d%d",&a,&b);
edge[a][b] = edge[b][a] = 1;
}
memset(dp,-1,sizeof(dp));
memset(way,0,sizeof(way));
int ii,jj;
long long temp;
for(int i = 1; i <= N; ++i)
for(int j = 1; j <= N; ++j){
if(i == j || !edge[i][j])continue;
ii = 1<<(i-1);
jj = 1<<(j-1);
temp = V[i]+V[j]+V[i]*V[j];
dp[ii+jj][i][j] = temp;
way[ii+jj][i][j] = 1;
}
for(int S = 0; S < (1<<N); ++S)
for(int i = 1; i <= N; ++i){
if((S&(1<<(i-1))) == 0)continue;
for(int j = 1; j <= N; ++j){
if((S&(1<<(j-1))) ==0 || i == j || !edge[i][j])continue;
for(int k = 1; k <= N; ++k){
if(i == k || j == k ||(S&(1<<(k-1))) == 0)continue;
int newS = S -(1<<(i-1));
if(dp[newS][j][k] ==-1)continue;
if(!edge[j][k])continue;
temp =V[i]+V[i]*V[j]+dp[newS][j][k];
if(edge[i][k])temp +=V[i]*V[j]*V[k];
if(dp[S][i][j] < temp){
dp[S][i][j] = temp;
way[S][i][j] =way[newS][j][k]; //如果dp更新,way直接更新
}
//如果dp不更新,但dp=temp,way加上原来的值
else if(temp ==dp[S][i][j])way[S][i][j] += way[newS][j][k];
}
}
}
long long ans = -1,num = 0;
int p = (1<<(N)) - 1;
for (int i = 1; i <= N; ++i)
for (int j = 1; j <= N; ++j){
if(i == j)continue;
if (ans < dp[p][i][j]){
ans = dp[p][i][j];
num = way[p][i][j];
}
else if (ans == dp[p][i][j])
num += way[p][i][j];
}
if(ans == -1){
puts("0 0");
continue;
}
printf("%lld %lld\n",ans,num/2);
}
return 0;
}
【ZOJ4257】MostPowerful
【题目大意】不超过10种气体,两两之间相互碰撞可以产生一定的能量,如a碰b,那么b气体就消失,自身不能碰自身,问最后所能得到的最大能量。
【题目解析】用10位二进制表示气体是否存在,0表示存在,1表示不存在,S(上一个状态)中的两种气体碰撞并且有一种消失,可以得到newS的状态(状态转移)
【状态表示】dp[state] 状态为state时的最大能量
【转移方程】dp[state] = max(dp[state],dp[state’]+a[i][j])
【边界条件】dp[i] = 0;
【代码】
#include <cstdio>
#include <cstring>
using namespace std;
#define max(a,b) (a) > (b) ? (a) : (b)
const int MAXN = 10;
const int MAX_S = 1 << 10;
int a[MAXN+1][MAXN+1];
int dp[MAX_S];
int N;
int main(){
while(scanf("%d",&N) != EOF){
if(N == 0)break;
for(int i = 0; i < N; ++i)
for(int j = 0; j < N; ++j){
scanf("%d",&a[i][j]);
}
memset(dp,0,sizeof(dp));
int full = 1 << N;
for(int s = 0; s < full; ++s){
for(int i = 0; i < N; ++i){
if((s&(1<<i)))continue;
for(int j = 0; j < N; ++j){
if(i == j)continue;
if( (s&(1<<j)) )continue;
int newS = s + (1<<j);
dp[newS] = max(dp[newS],dp[s] + a[i][j]);
}
}
}
int ans = 0;
for(int s = 0; s < full ; ++s)
ans = max(ans,dp[s]);
printf("%d\n",ans);
}
return 0;
}
【POJ2411】Mondriaan’sDream
【题目大意】一个矩阵,只能放1*2的木块,问将这个矩阵完全覆盖的不同放法有多少种。
【解析】如果是横着的就定义11,如果竖着的定义为竖着的01,这样按行dp只需要考虑两件事儿,当前行&上一行,是不是全为1,不是说明竖着有空(不可能出现竖着的00),另一个要检查当前行里有没有横放的,但为奇数的1。
【状态表示】dp[state][i]第i行状态为state时候的方案数
【转移方程】dp[state][i] += dp[state’][i-1] state’为i-1行的,不与i行状态state冲突的状态
【边界条件】第一行 符合条件的状态记为1 即dp[state][0] = 1;
【代码】
#include <cstdio>
#include <cstring>
using namespace std;
int M,N;
long long dp[1<<11][11];
bool kexing[1<<11];
int full;
inline bool check(int in)
{
int bit=0;
while(in>0){
if( (in&1)==1)
bit++;
else{
if( (bit&1)==1)
return false;
bit=0;
}
in>>=1;
}
if( (bit&1)==1)
return false;
return true;
}
inline bool check2(int x1,int x2){
if( (x1|x2)!= full-1 ) //如果这里不用位运算,时间很长,要用约3000MS
return false;
return kexing[x1&x2];
}
int main(){
full = 1<<11;
for(int s = 0; s < full; ++s)if(check(s))kexing[s] = 1;
while(scanf("%d%d",&M,&N) != EOF){
if(N == 0 && M == 0)break;
memset(dp,0,sizeof(dp));
full = 1<<N;
for(int s = 0; s < full; ++s){
if(kexing[s])
dp[s][0] = 1;
}
for(int i = 1; i < M; ++i){
for(int s = 0; s < full; ++s){
for(int s1 = 0; s1 < full; ++s1){
if(!check2(s1,s))continue;
//if(dp[s1][i-1] == 0)continue;
/*这一步判断的时间要大于位运算和+=的时间,如果先把这一步放在
check2前面,1300多MS,如果放在check2后面,610多MS,如果不加这
一步,560MS,但如果check2用的不是位运算,将这一步加在check2前
面3000MS左右(水过),如果不加这一步,TLE
*/
dp[s][i] += dp[s1][i-1];
}
}
}
int S = (1<<N) - 1;
printf("%lld\n",dp[S][M-1]);
}
return 0;
}
【HDU3681】PrisonBreak 状态压缩DP+BFS+二分答案
2010杭州赛区的题目,以现在的水平遇到这种题也就能想一下,赛场上动手写这个题是不会的。前天做状压DP的时候又看到这个题,没想起来怎么做,昨天看了一下解题报告开始下手,遇到了各种问题。调试了N久,终于过了。
【题目大意】机器人从F出发,走到G可以充电,走到Y关掉开关,D不能走进,要求把所有开关关掉,且电量最少,并求出该最小电量。
【题目解析】机器人从出发点出发要求走过所有的Y,因为点很少,所以就能想到经典的TSP问题(起初我也想到了),但关于G点(不要YY)能充电的问题不知道怎么办,看了下解题报告才知道。G点可以充电,到达G点就把当前能量更新为电池容量然后继续走。因为每个G点只能充一次电,这就好像TSP中的每个点只能走一次一样(G和Y都可以走多次,但走到G充电后,该点就变为了S,而走到Y关上开关以后,Y也变成了S。这是一个很巧妙地想法,所以要求Y点只能关一次开关,G点只能充一次电,这就是TSP了。Orz赛场上可以秒杀这题的大神们),然后就是二分答案了,用状压DP判定当前电池容量的情况下是否能符合条件。
【状态表示】dp[s][i]表示到达当前i点状态为s时最大的剩余的能量
【转移方程】同TSP问题了
【边界条件】dp[1<<sid][sid] = rongliang.即出发点的能量就是电池容量
【代码】:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define INF 0x1f1f1f1f
int dp[32769][16];
int dist[16][16][16][16];
int di[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
int M,N,sid,nCnt,FinalState;
char map[16][16];
struct node{
int x,y;
node(){}
node(int _x,int _y):x(_x),y(_y){}
}nodes[16];
inline void BFS(node start)
{
queue<node> que;
int sx = start.x,sy = start.y;
dist[sx][sy][sx][sy] = 0;
que.push(start);
node cur;
while(!que.empty()){
cur = que.front();
que.pop();
int x = cur.x,y = cur.y,tx,ty;
for(int i = 0; i < 4; ++i){
tx = x + di[i][0];
ty = y + di[i][1];
if(tx < 0 || tx >= M || ty < 0 || ty >= N || map[tx][ty] == 'D')continue;
if(dist[sx][sy][tx][ty] == -1){
dist[sx][sy][tx][ty] = dist[sx][sy][x][y] + 1;
que.push(node(tx,ty));
}
}
}
}
inline bool ok(int s,int t){ //s状态中走过所有t状态中的城市
if(((s&t)&t) == t)return 1;
return 0;
}
inline bool check(int step){
int res = -1;
memset(dp,-1,sizeof(dp));
dp[1<<sid][sid] = step;
int full = 1<<nCnt;
for(int s = 0; s < full; ++s){
for(int i = 0; i < nCnt; ++i){
if((s&(1<<i)) == 0 || dp[s][i] == -1)continue;
if(ok(s,FinalState))res = max(res,dp[s][i]);
for(int j = 0; j < nCnt; ++j){
int temp = dist[nodes[i].x][nodes[i].y][nodes[j].x][nodes[j].y];
if(i == j || temp == -1 || (s&(1<<j)))continue;
temp = dp[s][i] - temp;
if(temp < 0)continue;
int newS = s + (1<<j);
dp[newS][j] = max(dp[newS][j],temp);
if(map[nodes[j].x][nodes[j].y] == 'G')dp[newS][j] = step;
}
}
}
if(res < 0)return 0;
return 1;
}
inline int solve(){
int low = 0,high = 300;
int mid;
while(low <= high){
mid = (low+high)/2;
if(check(mid))high = mid-1;
else low = mid+1;
}
if(low == 301)return -1;
return low;
}
int main(){
while(scanf("%d%d",&M,&N) != EOF){
if(M == 0 && N == 0)break;
nCnt = 0;
FinalState = 0;
for(int i = 0; i < M; ++i){
scanf(" %s",map[i]);
for(int j = 0; j < N; ++j){
if(map[i][j] == 'F'){
sid = nCnt;
nodes[nCnt++] = node(i,j);
FinalState += (1<<sid);
}
else if(map[i][j] == 'G')
nodes[nCnt++] = node(i,j);
else if(map[i][j] == 'Y'){
int tid = nCnt;
nodes[nCnt++] = node(i,j);
FinalState += (1<<tid);
}
}
}
memset(dist,-1,sizeof(dist));
for(int i = 0; i < nCnt; ++i)BFS(nodes[i]);
int ans = solve();
printf("%d\n",ans);
}
return 0;
}
状态压缩DP(大佬写的很好,转来看)的更多相关文章
- HDU 4640 状态压缩DP 未写完
原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4640 解题思路: 首先用一个简单的2^n*n的dp可以求出一个人访问一个给定状态的最小花费,因为这i个 ...
- Travelling(spfa+状态压缩dp)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 Travelling Time Limit: 6000/3000 MS (Java/Others ...
- 浅谈状态压缩DP
浅谈状态压缩DP 本篇随笔简单讲解一下信息学奥林匹克竞赛中的状态压缩动态规划相关知识点.在算法竞赛中,状压\(DP\)是非常常见的动规类型.不仅如此,不仅是状压\(DP\),状压还是很多其他题目的处理 ...
- BZOJ1294 洛谷P2566 状态压缩DP 围豆豆
传送门 题目描述 是不是平时在手机里玩吃豆豆游戏玩腻了呢?最近MOKIA手机上推出了一种新的围豆豆游戏,大家一起来试一试吧游戏的规则非常简单,在一个N×M的矩阵方格内分布着D颗豆子,每颗豆有不同的分值 ...
- [知识点]状态压缩DP
// 此博文为迁移而来,写于2015年7月15日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102w6jf.html 1.前 ...
- hdu4336 Card Collector 状态压缩dp
Card Collector Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
- 状态压缩·一(状态压缩DP)
描述 小Hi和小Ho在兑换到了喜欢的奖品之后,便继续起了他们的美国之行,思来想去,他们决定乘坐火车前往下一座城市——那座城市即将举行美食节! 但是不幸的是,小Hi和小Ho并没有能够买到很好的火车票—— ...
- 学习笔记:状态压缩DP
我们知道,用DP解决一个问题的时候很重要的一环就是状态的表示,一般来说,一个数组即可保存状态.但是有这样的一些题 目,它们具有DP问题的特性,但是状态中所包含的信息过多,如果要用数组来保存状态的话需要 ...
- POJ 1691 Painting a Board(状态压缩DP)
Description The CE digital company has built an Automatic Painting Machine (APM) to paint a flat boa ...
随机推荐
- Linux网络安全篇,认识防火墙(二),Netfilter
一.概述 因为iptables软件利用的是数据包的过滤的机制.所以它会分析数据包的报头数据.根据报头数据与定义的规则来决定该数据是否可以放行.若数据包内容与规则内容相同则放行,否则继续与下一条规则进行 ...
- "一号标题"组件:<h1> —— 快应用组件库H-UI
 <import name="h1" src="../Common/ui/h-ui/text/c_h1"></import> < ...
- Python爬虫系列(六):搜索文档树
今天早上,写的东西掉了.这个烂知乎,有bug,说了自动保存草稿,其实并没有保存.无语 今晚,我们将继续讨论如何分析html文档. 1.字符串 #直接找元素soup.find_all('b') 2.正则 ...
- java 方法 在jvm中的调用
java 某个类的几个对象,这些对象调用类中一个函数,是各自拥有自己的函数代码还是使用同一段代码?30 1.java 某个类的几个对象,这些对象调用类中一个函数(普通的函数),是各自拥有自己的函数代码 ...
- java的图形化界面 文本区JTextArea的程序例子
package java1; //使用时这个改成你的包名即可//文本区 JTextArea import javax.swing.*;import java.awt.*;import java ...
- QMS产品 - MasterControl 质量管理活动
主要质量管理活动如下所示: CAPA 纠正措施/预防措施 Corrective Maintenance 纠正措施 Preventive Maintenance 预防措施 Customs Complai ...
- 计算机视觉中的对象检测,Python用几段代码就能实现
目前计算机视觉(CV)与自然语言处理(NLP)及语音识别并列为人工智能三大热点方向,而计算机视觉中的对象检测(objectdetection)应用非常广泛,比如自动驾驶.视频监控.工业质检.医疗诊断等 ...
- EOS基础全家桶(八)jungle测试网的使用
简介 前面我们已经学习了一些EOS的基础知识了,但是在EOS主网上的很多操作(比如:抵押.赎回.买卖内存)都是需要EOS链被正式激活后才可使用,而激活EOS链还需要很多的准备操作,我打算在单独的一篇文 ...
- [转载]MySQL中int(11)最大长度是多少?
原文地址:https://blog.csdn.net/allenjay11/article/details/76549503 今天在添加数据的时候,发现当数据类型为 int(11) 时,我当时让用户添 ...
- jquary 动画j
1) 点击 id为d1的正方体,将其后所有class为div1的正方体背景色设置为绿色. 代码如下: <div class="div1" > </di ...