1. 程式人生 > >幸運數字1

幸運數字1

ostream memset space printf 下標 mes n) 位數 truct

幸運數字

題目描述:

小紅最近迷上了幸運數字。他所認為的幸運數字是指只由4或7組成的數字比如44, 7774, 4就是幸運數字, 而5,17, 4437等就不是。現在他想知道一個最小的幸運數字, 使得這個數字的各個位數字之和等於n。 輸入描述: 第一行輸入一個數字, n;n大於等於1 小於等於1000000 代表小紅想要的數字之和。 輸出描述: 輸出最小的那個幸運數字, 如果不存在, 那麽輸出-1。 題解: 首先這道題我們可以寫一個擴展歐幾裏得,因為數據範圍還是比較小,就設4的個數為x,7的個數為y,4x + 7y = n,我們需要使x + y的值盡可能小,使7的個數盡可能多。
但下面我們來寫一種dp寫法,我們定義一個結構體變量dp[ i ],其中包含的元素有cnt:數的位數,val:4的個數加上七的個數乘上一個常數1000000 / 4 ,還需要一個數 to[ i ]表示當前是在更新4 or 7,還需要一個e數組表示當前val要加上多少; dp[ i ]數組的下標表示數的各位數字之和,然後我們就可以得到dp狀態轉移方程: w.cnt = dp[ i - to[ j ] ] + 1; w.val = dp[ i - to[ j ] ] + e[ j ]; dp[ i ] = min ( dp[ i ] , w ); 這裏的min()需要自己重新定義結構體比較,返回位數小的,若位數一樣,返回7更少的,即val更大的。
具體解釋見代碼註釋:
#include<cstdio>
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int N = 1e6 + 1;

struct node{
  int cnt,val;
}dp[N];

int n, to[2] = {4,7}, e[2] = {1,1000000 / 4};//e[]的用處是將4的個數和7的個數都巧妙地存起來,存在val中

node min(node a, node b){
  if (a.cnt == b.cnt) return
a.val < b.val ? a : b;//如上文 return a.cnt < b.cnt ? a : b; } void spfa(){ memset(dp, 0x3f, sizeof(dp)); dp[0].cnt = dp[0].val = 0; for (int i = 1; i <= 100000; i++) for (int j = 0; j < 2; j++){ if (i - to[j] < 0) continue; node w; w.cnt = dp[i - to[j]].cnt + 1; w.val = dp[i - to[j]].val + e[j];//每次j = 0就加上1,而j = 1的時候就加上1000000/4
這樣val/(100000/4)就是7的個數,而val%(100000/4)
就是4的個數 dp[i]
= min(dp[i], w); } } int main(){ spfa();//先處理處1~1000000的值,預處理,然後查詢 scanf("%d", &n); if (dp[n].cnt > e[1]){//表示求出的位數超過了最大位數,就說明找不到 printf("-1"); return 0; } int four = dp[n].val % e[1]; int seven = dp[n].val / e[1]; for (int i = 1; i <= four; i++) printf("4"); for (int i = 1; i <= seven; i++) printf("7"); return 0; }

幸運數字1