状态压缩dp例题

POJ  2411 Mondriaan's Dream

题意:求n*m的矩阵分成若干个1*2的长方形,有多少种方案

思路:假设以矩阵的某一行分界,分界线的上面一行有二种状态,一种为一个竖立的1*2的上半部分即:这个格子还没有拼好,一种为已经拼好了这个格子,我们计没有拼好的那种格子状态为1,拼好的状态为0,当且仅当上面一行(j)可以转移到下面一行(k),状态要满足  1:j&k==0 这样保证了上面格子为1,那么下面对应的格子为0   2:j|k表示的二进制数连续的0为偶数,这些0表示下面一行横着的长方形的状态,为奇数不能分割

POJ 1185  炮兵阵地

题意:给一个n*m矩阵,二种状态可以放炮兵,不能放炮兵,每个炮兵的攻击范围在上下左右2个格子范围内,求这个矩阵最多可以放多少个炮兵

思路:以行为阶段状态压缩dp,dp[i][j][k]表示当第i行状态为j时,i-1行状态为k时,前i行最多可以放多少个炮兵,然后判断一下状态的条件即可

poj 3311 Hie with the Pie

题意:给n+1个点从0到n,求从0出发再回到0的最短距离,每个点至少经过一次;

思路:经典的tsp问题,正解是先用floyd 求出i,j二点的最短路,再状态压缩dp;

但是我没有求最短路 这样也过了。。。数据水了

for(int k=0;k<1<<m;++k)
		{
			for(int i=0;i<=n;++i)
			{
				for(int x=0;x<=n;++x)
				{
					int j=k^(1<<x);
					dp[i][k]=min(dp[i][k],dp[x][j]+c[x][i]);
				}
			}
			for(int i=0;i<=n;++i)
				for(int x=0;x<=n;++x)
					dp[i][k]=min(dp[i][k],dp[x][k]+c[x][i]);
				
		}

HDU 3001 Travelling

题意:给n个点,从1到n,求从任意点出发,每个点至多经过二次并且每个点至少经过1次的最小花费;

思路:3进制的tsp问题

hdu 2167 Pebbles

题意:给一个n*n的矩阵,现在让你选一些数,限制为不能选相邻的数(上下左右),求选出来的数权值和最大是多少;

思路:n是小于20的,肯定不能n*(1<<n)*(1<<n) 其实他有效的状态很少,那么就将有效的状态存起来即可,这个题目会超内存;

用滚动数组优化就行了

codeforces 417D Cunning Gena

题意:有n个人,m个任务,连接一台电脑要b 钱,每个人可以做一些任务,要用一个人,要花xi钱,且连接的电脑要ki台,这个人能完成mi个任务(每个任务有一个序号),求完成这m个任务最少要花费多少钱。

思路:状态压缩+背包  如果没有ki的影响就是一个sb题目,然后发现有ki,将ki从小到大排序,然后就转发成没ki的情况了 利用01背包的原理,dp[i][s]表示前i个人,完成任务的状态为s的最小花费。

codeforces 1209E2 Rotate Columns (hard version)

题意:给一个n*m的矩阵,这个矩阵的每一列都可以向下移动一格,既1->2 2->3 n->1 ,可以操作无限次;求最终矩阵的每一行的最大值之和;n<=12 m<=2000

思路:假设n<=m 可以看出有用的列为n个,假设每一列的权值为每一列的最大值,那么只有前n大的列才能贡献答案;那么就可以将m降到12;    进行状态压缩dp;dp[i][s]表示前i列s的二进制为1的那行确定时的最大值  那么dp[i][s]=max(dp[i][j]+dp[i-1][s-j])其中j为i的确定行的子集 1011的子集有(1011 1001 1010 1000 0000);有一个枚举子集的 方法  for(int k=j;k;k=(k-1)&j) ;这样k就能枚举j的所有子集;

codeforces 1215E Marbles

题意:给n个数(n<=4e5),a[i]<=20,有一种操作,就是互换相邻的二个数,求将这n个数分成k段,其中每一段为一种数,且那种数都在这一段的最小操作次数;

思路:这个题目a[i]只有20,可以考虑状态压缩dp,dp[s]表示当状态s的二进制位为1的那些位已经确定的时候的最少操作次数;

那么if((1<<j)&s==0)dp[s]=min(dp[s^(1<<j)]+sum) sum为将第j位移到s状态中为1的那些位前面的最少操作次数和;可以预处理出c[i][j]表示将所有i移动所有j前面 的次数,输出dp[(1<<20)-1];

codeforces 543C  Remembering Strings

题意:给n个长度为m的字符串,一个好的字符串定义为在其它的字符串第i个位置,没有与这个字符串的第i个位置字符相同,一个字符串有一个位置i满足就是好的字符串;ai,j 表示修改第i个字符串第j个字符的代价,现在要你改一些字符,使所有字符串都是好的的最小花费;

思路:用类似tsp枚举所有的字符串的状态,1表示那个位置的字符串是好的,dp[s]表示状态s的时候的最小花费,那么s状态中所有为0的字符串都可以变好,假设要把第j个字符串变好,考虑字符串j的所有位置的字符,假设第k个字符,要么把j,k变了,要么把所有字符的第k位和j字符串的第k位相同的字符除最大值都变了这二种变法;

 

codeforces 152E Garden 

题意:在一些n*m的网格中 每个格子里面都有一些不同数量的花 问现在要使得一些给定的重要位置联通 你需要破坏至少多少花来使得道路联通

思路:最短路+状态压缩dp dp[x][y][s]表示在x,y这个点重要点的状态是s的时候最少破坏花的数量,然后进行迪杰斯特拉,状态转移 dp[xx][yy][s|j]=dp[xx][yy][j] +dp[x][y][s] 其中j是与s没有相同的1的全集,输出路径找到一个最小的连接所有重要点的点进行输出  按状态转移方程走,可能有多个答案,输出一个就行了;ac代码  https://paste.ubuntu.com/p/5xDFTsgchB/

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值