CF302E:Remembering Strings 状态压缩DP

本文介绍了一道编程题目CF302E的解决方案,该问题旨在找到让每行字符满足特定条件所需的最小修改费用。通过状态压缩和动态规划的方法,实现了高效的求解。

CF302E

题意

  • 每一行为好记满足:在这一行至少有一个字母在这一列是只出现一次的。
  • 修改每一个字母都要费用,求使每一行都好记的最小费用。

题解

  • 使一行的字母好记,可以修改某一个字母,或者修改这一列的与这个字母相同的字母,并保留花费最大。
  • 状态压缩枚举,dp[i]表示状态i的最小花费。i中1表示好记,0表示不好记。我们不用判断这一行是否已经是好记,直接暴力枚举。如果好记,根据上面的修改方案,花费就是0。

代码

#include <bits/stdc++.h>
using namespace std;
int const N = 20 + 2;
int const inf = 0x7f7f7f7f;
char s[N][N];
int n,m;
int a[N][N],sum[N][N],state[N][N];
int dp[1<<N];
int main(){
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++)
		scanf(" %s",s[i]);
	for(int i=0;i<n;i++)
		for(int j=0;j<m;j++)
			scanf("%d",&a[i][j]);
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){  //找与s[i][j]同列的相同的字母的总花费
			int mx = -1;
			for(int k=0;k<n;k++){   
				if(s[i][j] == s[k][j]){
					mx = max(mx,a[k][j]);
					state[i][j] |= (1<<k);
					sum[i][j] += a[k][j];
				}	
			}
			sum[i][j] -= mx;   //如果没有相同的字母,那么sum[i][j]显然为0,修改不花费代价
		}
	}
	memset(dp,inf,sizeof(dp));
	dp[0] = 0;   //初始化
	for(int i=0;i<(1<<n);i++){    //枚举n行的状态,1表示好记,0表示不好记
		for(int j=0;j<n;j++){  //遍历每一行
			if((i&(1<<j)) == 0){  //假设第j行不好记
				for(int k=0;k<m;k++){   //考虑第j行的每一字母
					if(dp[i] == inf)	continue;
					dp[i|(1<<j)] = min(dp[i|(1<<j)],dp[i] + a[j][k]);  //修改一行中的一个使其变为好记
					dp[i|state[j][k]] = min(dp[i|state[j][k]],dp[i] + sum[j][k]);  //修改和自己相同的,并保留最大的
 				}
			}
		}
	}
	printf("%d\n",dp[(1<<n)-1]);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值