牛客-牛牛的计算机内存

题目描述

牛牛的计算机一共有m块内存,现在有n条指令,每条指令是一个01序列

如果指令的第i个字符为1,说明这条指令需要访问第i块内存,从0开始

每条指令的执行代价为k^2, k为新访问内存的数量,即之前的指令都没有访问到的内存数量

你可以随意安排n条指令的执行顺序,求执行完所有指令的最小代价

输入描述

第一行先输入一个整数n和m(1≤n,m≤20)

接下来每行输入一个01字符串,长度不超过20

输出描述

输出一个整数

输入样例 1 

3 3
111
001
010

输出样例 1

3

输入样例 2 

5 5
11101
00111
10101
00000
11000

输出样例 2

9

输入样例 3 

3 4
1000
1100
1110

输出样例 3

3

备注:

子任务1:n <= 5
子任务2:n <= 10
子任务3:无限制

解题思路

题目说可以随意安排指令的顺序,我试过暴力总是会超时,最多为75.92%

不行就换一种想法吧,我们可以试一试状态压缩,我觉得状态压缩其实和暴力有点像

我们可以用一个二进制表示的数字来表示指令的执行状态,假设有5条指令,那就用一个长度为5的二进制数字存储指令的执行状态,数为xxxxx,从右往左数,如果当前位上为1表示第i条指令被执行过,反之则没有

用一个数组dp[i]来表示执行状态为i时的最小执行代价,mem[i]表示执行指令状态为i时已被访问的内存

则我们就可以用两个for循环嵌套,第一个枚举状态,第二个枚举指令,当发现状态和指令不匹配时,将执行指令后的代价与状态最小代价比较(状态为之前状态加上指令得来),获取最小的

核心代码

	for(int j=0;j<(1<<n);j++){//枚举状态 
		for(int k=0;k<n;k++){//枚举指令 
			if(!(j&(1<<k))){//当状态和指令不匹配时
				int ans=dp[j]+solve(mem[j],sme[k]);//获取执行指令后的代价
				if(dp[j|(1<<k)]>ans){//与状态的当前最小代价相比较
					dp[j|(1<<k)]=ans;
					mem[j|(1<<k)]=mem[j]|sme[k];
				} 
			}
		}
	}

其中的solve为函数,是用来解决在当前状态下执行指令的执行代价

函数体

int solve(int a,int b){//求出在当前状态下执行指令的执行代价
	int ans=0;
	for(int i=0;i<m;i++){
		if((a&(1<<i))==0&&(b&(1<<i))) ans++;//当内存不匹配时加1
	}
	return ans*ans;
}

题解代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
int dp[(1<<20)+5],mem[(1<<20)+5];// dp[i]表示执行的指令状态为i时的最小代价,mem[i]表示执行指令状态为i时已被访问的内存
int sme[22];//标记每条指令访问那些内存
char s[22];
int n,m;
int solve(int a,int b){//求出在当前状态下执行指令的执行代价
	int ans=0;
	for(int i=0;i<m;i++){
		if((a&(1<<i))==0&&(b&(1<<i))) ans++;//当内存不匹配时加1
	}
	return ans*ans;
}
int main(){
    cin>>n>>m;
    for(int i=0;i<n;i++){
    	cin>>s;
    	for(int j=0;j<m;j++){//标记每条指令访问那些内存
    		if(s[j]=='1') sme[i]=sme[i]|(1<<j);		
		}
	}
	memset(dp,INF,sizeof(dp));
	dp[0]=0;
	for(int j=0;j<(1<<n);j++){//枚举状态 
		for(int k=0;k<n;k++){//枚举指令 
			if(!(j&(1<<k))){//当状态和指令不匹配时
				int ans=dp[j]+solve(mem[j],sme[k]);//获取执行指令后的代价
				if(dp[j|(1<<k)]>ans){//与状态的当前最小代价相比较
					dp[j|(1<<k)]=ans;
					mem[j|(1<<k)]=mem[j]|sme[k];
				} 
			}
		}
	}
	cout<<dp[(1<<n)-1]<<endl;
	return 0;
}
 
 
 

其实状态压缩我也不是很懂,大家可以多评论评论,我们有不懂的可以多交流交流

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值