【USACO題庫】3.1.6 Stamps郵票
阿新 • • 發佈:2018-12-16
這一道題,算是我“千辛萬苦”才做出來的吧。因為,我在時超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;
}