牛客练习题---21873:牛牛的计算机内存【状压dp】

链接:https://ac.nowcoder.com/acm/problem/21873
来源:牛客网

题意:

牛牛的计算机一共有m块内存,现在有n条指令,每条指令是一个01序列
如果指令的第i个字符为1,说明这条指令需要访问第i块内存
每条指令的执行代价为k^2, k为新访问内存的数量,即之前的指令都没有访问到的内存数量
你可以随意安排n条指令的执行顺序,求执行完所有指令的最小代价

输入:

第一行先输入一个整数n,m(1 ≤ n ≤ 20)
接下来每行输入一个01字符串,长度不超过20

分析:

因为可以随意安排执行顺序,暴力就是20!,必然TLE,从记忆化搜索可以得到动态规划的做法

定义dp[i][j],表示执行完前i次后状态为j的最小代价,状态j是什么呢?就是将前i次选的i条指令的编号压缩成一个数j,比如j的二进制为(110),就代表前2次分别执行了编号为12的指令

定义val[i][j]表示到达dp[i][j]时,所选的指令所代表的字符串的状态,可以将每条指令看成一个二进制字符串,再将它压缩成十进制数表示状态,注意开滚动数组,否则要MLE

代码:

#include 

using namespace std;
const int inf = 0x3f3f3f3f;
int a[22],n,m,dp[2][1<<20],val[2][1<<20];
string s[22];
int cal(int x)                 //将二进制字符串压缩成十进制数
{
    int res = 0,b = 1;
    for(int i = 0;i < m; ++i,b <<= 1) res += (s[x][i]=='1' ? b : 0);
    return res;
}
int cal2(int a,int b)          //计算a->b要花费的代价
{
    int res = 0;
    for(int i = 0;i < 22; ++i){
        if((a & (1<>n>>m;
    memset(dp,inf,sizeof(dp));
    for(int i = 0;i < n; ++i) cin>>s[i];
    for(int i = 0;i < n; ++i){
        a[i] = cal(i);
        dp[0][1<

上面的代码更具逻辑性,考虑当执行了一些指令后,下一次必然执行还未执行的一条指令,定义dp[j] 表示到达状态j时的最小花费,也就是执行了某些指令的最小花费,最后答案为dp[(1<

代码:

#include 
  
using namespace std;
const int inf = 0x3f3f3f3f;
int n,m,a[22],dp[1<<20],val[1<<20];
char s[22];
int cal(int x)                 //将二进制字符串压缩成十进制数
{
    int res = 0,b = 1;
    for(int i = 0;i < m; ++i,b <<= 1) res += (s[i]=='1' ? b : 0);
    return res;
}
int cal2(int a,int b)          //计算a->b要花费的代价
{
    int res = 0;
    for(int i = 0;i < 22; ++i){
        if((a & (1<> n >> m;
    for(int i = 0;i < n; ++i) cin >>s,a[i] = cal(i);
    memset(dp,inf,sizeof(dp));
    dp[0] = 0;
    for(int j = 0; j < (1< tep){
                    dp[j|(1<

 

你可能感兴趣的:(动态规划----状压dp,题解----牛客网)