CS 400 Seven-egment Display 贪心+模拟,DP

53 篇文章 0 订阅
34 篇文章 0 订阅

CS 400
题意:a[i]:数字i需要的火柴个数[i=0..9] 问正好用k个火柴时 最小能拼成的数是多少? k<=1e5.
a[]={6,2,5,5,4,5,6,3,7,6}.
首先位数尽量小,总共位数为k/7位.
剩下r=k%7个火柴{0~6} 分别讨论一下 例如r=1时 拆掉一个7 现在用8个火柴 放一个1和0.即可.
现在位数确定了 但是数还可以减小 例如k=10 得到78 但可以减小到22.
也就是说最高位火柴不一定用r个,假如放了x个 x>r 否则后面要增加.
现在有7+r个火柴.暴力拆分成最优的两个即可. 接着从高到低对每位都做同样的贪心.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int mp[30]={0,-1,1,7,4,2,0,8};
int rp[30]={6,2,5,5,4,5,6,3,7,6};
vector<int> res;
void work(int op,int pos,int r)
{
	int a=10,b=10;
	for(int i=2;i<=7;i++)
	{
		int j=r-i,ta=mp[i],tb=mp[j];
		if(j>7)
			continue;
		if(op==0&&i==6)
			ta=6;
		if(ta<a||ta==a&&ta<b)
			a=ta,b=tb;
	} 
	if(op)
		res[pos]=a,res[pos-1]=b;
	else
		res.push_back(b),res.push_back(a);
}
int main()
{
	int k;
	cin>>k;
	if(k<=7)
		cout<<mp[k]<<endl;
	else
	{
		int tot=k/7,r=k%7;
		if(r!=0)
			tot--;
		for(int i=0;i<tot;i++)
			res.push_back(8);
		if(r==1)
			res.push_back(0),res.push_back(1);
		else if(r!=0)
			work(0,0,7+r);
		for(int i=res.size()-2;i>=1;i--)
			work(1,i,7+rp[res[i]]);		
		for(int i=res.size()-1;i>=0;i--)
			printf("%d",res[i]);		
	}	
	return 0;
}

DP:dp[i]表示i个火柴最少拆成多少个数字. 每次从高位开始选一个数字i 若dp[k]>=d[i]&& dp[k-d[i]]=dp[k]-1 则选择即可

DP来自某大佬代码

#include<stdio.h>
#include<string.h>
const int d[10]={6,2,5,5,4,5,6,3,7,6};
int dp[111111],K;
void upd(int&x,int y){
	if(x==-1 || x>y)x=y;
}
int main(){
	scanf("%d",&K);
	if(K == 6){
		puts("0");
		return 0;
	}
	memset(dp,-1,sizeof(dp));
	dp[0] = 0;
	for(int i=0; i<K; i++)if(dp[i] != -1)
		for(int j=0; j<10; j++)
			upd(dp[i+d[j]],dp[i]+1);
	if(dp[K] == -1)puts("-1");else{
		bool fir = false;
		while(K){
			for(int i=(fir?0:1); i<10; i++)
				if(K >= d[i] && dp[K - d[i]] == dp[K] - 1){
					K -= d[i];
					putchar(i+'0');
					break;
				}
			fir = true;
		}
		puts("");
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值