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;
}