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/