CF-div2-637-D. Nastya and Scoreboard | dp 贪心 记忆化搜索

思路1

dfs记忆化搜索

思路2

dp + 贪心

  1. 预处理val[i][j] 第i个做成数字j点亮的花费

  2. dp[i][cnt]表示 从后往前到第i个一共使用了cnt根能否凑出数字
    假设第i个凑成数字j花费了cost,
    那么dp[i][从后往前到第i个花费] |= dp[i+1][从后往前到第i+1个的花费-cost]


cost是能固定的,不固定的是前i个一共花费了多少
即当前这一轮凑成数字j的花费是固定的cost个,不固定的是 从后往前到第i个一共的花费

枚举 从后往前到第i个一共的花费了多少
那么dp[i][到i个一共的花费] |= dp[i+1][到i个一共的花费 - 第i个的cost花费]

dp代码

#include<bits/stdc++.h>
using namespace std;
 
const int inf = 0x3f3f3f3f;
const int maxn = 2e3+100;
const string str[] = {"1110111","0010010","1011101","1011011","0111010","1101011","1101111","1010010","1111111","1111011"};
 
string s;
 
int val[maxn][10];
int dp[maxn][maxn];

 
void init(int pos){
	for(int i=0;i<=9;i++){
		bool flag=false;
		int cnt=0;
		for(int j=0;j<7;j++){
			if(str[i][j]!=s[j]){
				if(s[j]=='1'){
					flag=true;
					break;
				}
				cnt++;
			}
		}
		if(flag) val[pos][i] = -1;
		else val[pos][i] = cnt;
	}
}

 
int main(){
	int n,k;
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++){
		cin>>s;
		init(i);
	}
	dp[n+1][0]=true; //初态: 第n+1花费0个 
	for(int i=n;i>=1;i--){
		for(int j=0;j<=9;j++){ //第i行凑出数字j 
			int cost = val[i][j]; //第i行花费cost凑出了数字j 
			if(cost == -1) {
				dp[i][cost] = 0;
				continue;
			}
			for(int t = cost;t<=k;t++){ 
				dp[i][t] |= dp[i+1][t-cost]; 
			}
		}
	}
	if(!dp[1][k]) return 0*puts("-1");
	
	//贪心找最大的 
	string ans;
	for(int i=1;i<=n;i++){
		for(int j=9;j>=0;j--){
			if(val[i][j]!=-1 && dp[i+1][k-val[i][j]] == 1){
				k -= val[i][j];
				ans += to_string(j);
				break;
			}
		}
	}
	cout<<ans<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/fisherss/p/12778911.html