zz大人说这是一道简单的 状态压缩DP ...个人表示我理解了好................................长时间..哭~
题意:
给出一个 n 表示有 n 道题..
然后给出 一个 n*n 的矩阵S..其中S( i j )表示 先做 j 题后做 i 题的 ac 系数值..
定义:设S(ij)表示第 i 题在第 j 题做完后才做获得的AC系数,有三道题a, b, c,做题顺序为bac,则系数和为:Sum = Sab + Scb + Sca。
求能够获得的最大 ac 系数和..
思路:
用两个数组..
f[ st ][ k ] 表示 做 k 题 以前做了的题的ac系数和..
dp[ st ][ k ] 表示 做完 k 题后的ac系数和..
其中 st 代表当前状态<做了的题和没做的题..> 这就是状态压缩的特殊所在..
zz大人语录:
状态压缩DP一般是用在总的情况比较少的时候..
比如这题 总的状态数 最多是 1<<16..
总的情况数比较少
所以可以枚举 ,而枚举 一般采用 二进制 ,这样比较快一些
可以看成是一种暴力枚举
意思就是就像 st ..它被运算成了二进制的形式..当 转换为 110 的时候就是 第一第二道题做了 第三道题没做..
而判断是否在这个状态的方法就是 if(( 1<<k ) & i)
如果状态 i 中包含 k这个状态
通过 2 层循环就可以找出 i 中出现的 k ..
即在 st 状态下 k 这道题有没有做..
Tips:
初始条件: dp[ ][ ] 都为-1 dp[ 1<<i ][ i ] = 0 表示所做了的题包含 i 题状态下 dp 值为 0
动态转移方程: dp[stat][k]=f[s][k]+max(dp[s][j]) stat 里面包含了 s + k 就是在s这个状态下做了的题再加上第 k 题..
结果: 遍历所有的dp[ st ][ 题 ] 找出最大值..
Code:
#include <stdio.h>
#include <cstring>
#include <fstream>
using namespace std;
int dp[1<<16][20], s[20][20], f[1<<16][20];
int main()
{
int i, j, k;
int st, ma, sts;
int n;
freopen("e:\\acm\\mess\\stdin-stdout\\in.txt", "r", stdin);
while(scanf("%d", &n) != EOF)
{
///***Initial***///
st = (1<<n) - 1; ///!!!
ma = 0;
memset(dp, -1, sizeof(dp)); ///mean it is without this state
memset(f, 0, sizeof(f));
for(i = 0; i < n; ++i)
dp[1<<i][i] = 0; ///mean the state with i is 0
///***Input***///
for(i = 0; i < n; ++i)
for(j = 0; j < n; ++j)
scanf("%d", &s[i][j]);
///*** change state of the f[][] ***///
for(i = 0; i < st; ++i){ ///always the first circulate is contral the first dimension variable
for(j = 0; j < n; ++j){
if(!(i&(1<<j)))
for(k = 0; k < n; ++k)
if(i&(1<<k))
f[i][j] += s[j][k]; /// make f[][j] include all value of the project do before j
}
}
///***change state of the dp[][]***///
for(i = 0; i < st; ++i)
for(j = 0; j < n; ++j)
if(dp[i][j] >= 0){
ma = 0; ///!!!
for(k = 0; k < n; ++k)
if(i&(1<<k)) ///k project is belong to this state
ma = max(ma, dp[i][k]);
for(k = 0; k < n; ++k){
if(i&(1<<k)) continue;
if(!(i&(1<<k))){ ///k project isn't belong to this state
sts = i+(1<<k);
dp[sts][k] = ma+f[i][k];
}
}
}
ma = 0;
///***find the max value ***///
for(i = 0; i < n; ++i)
ma = max(ma, dp[st][i]);
///***Output***///
printf("%d\n", ma);
}
return 0;
}
还没submit..因为几乎和 zz 大人的代码一样..囧~~
所以等我某一天突然做DP的时候再做这道题..然后再submit..
嗯嗯~~今天开始图论了~~~加油~!!!!!