1. 程式人生 > >【USACO題庫】3.1.6 Stamps郵票

【USACO題庫】3.1.6 Stamps郵票

這一道題,算是我“千辛萬苦”才做出來的吧。因為,我在時超70後代寫了很久,才找出了一個能對但又不超時的方法。
下邊,來說一說我的超時思想:
用i來列舉,從1一直到2000000,在一個個判斷,知道i不可以結合出來就輸出並結束程式,(呵呵,不超時的話,那就是相當於中了2億元的大獎了)
好了看一看超時代嗎:
#include<cstdio>
using namespace std;
int a[51],f[2000001];
bool bz[2000001];
int k,n;
bool pd(int x)
{
    int i;
    f[x]=666666666;
    for (i=1;i<=x/2
;i++) { if (bz[i]==true&&bz[x-i]==true) { bz[x]=true; if (f[x]>f[i]+f[x-i]) f[x]=f[i]+f[x-i]; } } if (f[x]>k) return false; else return bz[x]; } int main() { int i,j; scanf("%d%d",&k,&n); for (i=1;i<=n;i++) { scanf
("%d",&a[i]); for (j=1;j<=k;j++) { bz[a[i]*j]=true; f[a[i]*j]=j; } } for (i=1;i<=2000000;i++) { if (bz[i]==true) continue; else { if (pd(i)==true) continue; else { printf
("%d\n",i-1); return 0; } } } printf("%d\n",i-1); return 0; //那個bz陣列只是一個我自認為可以加一加速度的判斷陣列而已,不用在意這些細節。 }
好了,現在來說一說不會超時的簡潔的短型程式碼吧!
其實是這樣的:
f[i]表示的是湊成i分最少要多少張郵票,就是如下:
    for (i=1;i<=2000000;i++)
    {
        f[i]=666666666;
        for (j=1;j<=n;j++)
        {
            if (i-a[j]>=0&&f[i]>f[i-a[j]]+1) f[i]=f[i-a[j]]+1;
        }
    }
十分簡單明瞭,下面來看一看判斷語句吧:
    if (f[i]>k)
    {
        printf("%d\n",i-1);
        return 0;
    }
是不是很簡單,有沒有想明白呢?
其實,這些USACO的題目是比較適合那些需要提高思維能力的人去做的,因為只有做了以後,你才能在思維上有了質的飛越,希望多多思考,爭取能夠獨立完成USACO的所有題!

好了,廢話也就說完了,下面來出一下完整程式碼:
#include<cstdio>
using namespace std;
int a[51],f[2000001];
int k,n;
int main()
{
    int i,j;
    scanf("%d%d",&k,&n);
    for (i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for (i=1;i<=2000000;i++)
    {
        f[i]=666666666;
        for (j=1;j<=n;j++)
        {
            if (i-a[j]>=0&&f[i]>f[i-a[j]]+1) f[i]=f[i-a[j]]+1;
        }
        if (f[i]>k)
        {
            printf("%d\n",i-1);
            return 0;
        }
    }
    printf("%d\n",i-1);
    return 0;
}