1. 程式人生 > >Too Rich(貪心)

Too Rich(貪心)

題意:

現在你有P元錢,有10種不同面值的硬幣,每種硬幣有一定的數量,求用盡量多的硬幣湊出P元錢,如果湊不出輸出“-1”。

 題解:

  • 一、貪心(反向) (可以看下:一位大佬十分詳細的題解反向:求出所有硬幣的總價值(sum)- 所求的價值(P),問題轉化成用盡可能少的硬幣去湊出這個差值(sum-P);貪心思想:從面值大的硬幣開始,儘可能多地使用大面值硬幣;演算法核心:因為(20\rightarrow50)和(200\rightarrow500)不是整數倍的關係,所以不能直接貪心,那麼就需要轉化問題;當取偶數個50,可以用20拼湊出來,但取奇數個50時,用20是拼湊不出來的。 我們可以列舉以下四種情況: (50和500都是偶數個,不先取50和500) (50為奇數個,500為偶數個,即我們先取一個50) (50為偶數個,500為奇數個,即我們先取一個500) (50為奇數個,500為奇數個,即我們先取一個50和一個500) 之後對於50和500都成對地取,每次取50或500的時候就取偶數個。然後就可以用貪心了。
    #include <set>
    #include <map>
    #include <cmath>
    #include <stack>
    #include <queue>
    #include <vector>
    #include <string>
    #include <cstdio>
    #include <cstring>
    #include <sstream>
    #include <iomanip>
    #include <iostream>
    #include <algorithm>
    #define clr(str,x) memset(str,x,sizeof(str))
    #define FRER() freopen("in.txt","r",stdin);
    #define FREW() freopen("out.txt","w",stdout);
    #define INF 0x7fffffff
    #define maxn
    
    typedef long long int ll;
    using namespace std;
    int have[12],c[12],val[10]= {1,5,10,20,50,100,200,500,1000,2000};
    int consthave[12];
    int solve(int t)
    {
        int ans=0;
        for(int i=9; i>=0; i--)
        {
            if(i==4||i==7)
            {
                int temp = min(t/(2*val[i]),have[i]/2);
                ans += temp*2;
                t -= val[i] * 2 * temp;
            }
            else
            {
                int temp = min(t/val[i],have[i]);
                ans += temp;
                t -= val[i] * temp;
            }
            if(t==0)
                break;
        }
        if(t>0)
            return INF;
        else return ans;
    }
    int main()
    {
        //FRER()
        //FREW()
        int T,p;
        scanf("%d",&T);
        while(T--)
        {
            int sum=0,tol=0;
            scanf("%d",&p);
            for(int i=0; i<10; i++)
            {
                scanf("%d",&consthave[i]);
                sum+=consthave[i]*val[i];
                tol+=consthave[i];
            }
            sum-=p;
            if(sum<0)
            {
                printf("-1\n");
                continue;
            }
            int ans = INF;
            for(int i=0; i<2; i++)
            {
                for(int j=0; j<2; j++)
                {
                    memcpy(have,consthave,sizeof(consthave));
                    int t=sum;
                    if(i)
                    {
                        if(have[4])
                            t-=50,have[4]--;
                        else
                            continue;
                    }
                    if(j)
                    {
                        if(have[7])
                            t-=500,have[7]--;
                        else
                            continue;
                    }
                    if(t>=0)
                        ans=min(ans,solve(t)+i+j);
                }
            }
            if(ans==INF)
                printf("-1\n");
            else
                printf("%d\n",tol-ans);
        }
        return 0;
    }
  • 第二種貪心做法,有點類似搜尋。  

    #include <set>
    #include <map>
    #include <cmath>
    #include <stack>
    #include <queue>
    #include <vector>
    #include <string>
    #include <cstdio>
    #include <cstring>
    #include <sstream>
    #include <iomanip>
    #include <iostream>
    #include <algorithm>
    #define clr(str,x) memset(str,x,sizeof(str))
    #define FRER() freopen("in.txt","r",stdin);
    #define FREW() freopen("out.txt","w",stdout);
    #define INF 0x3f3f3f3f
    #define maxn
    
    typedef long long int ll;
    using namespace std;
    int have[10],val[]= {1,5,10,20,50,100,200,500,1000,2000};
    int consthave[10];
    int solve(int t)
    {
        int ans=0;
        for(int i=9; i>=0; i--)
        {
            if(i==4||i==7)
            {
                int temp = min(t/(val[i]*2),have[i]/2);
                ans += temp*2;
                t -= val[i] * 2 * temp;
            }
            else
            {
                int temp = min(t/val[i],have[i]);
                ans += temp;
                t -= val[i] * temp;
            }
            if(t==0)
                break;
        }
        if(t>0)
            return INF;
        else return ans;
    }
    
    int main()
    {
        //FRER()
        //FREW()
        int T,p;
        scanf("%d",&T);
        while(T--)
        {
            int sum=0,tol=0;
            scanf("%d",&p);
            for(int i=0; i<10; i++)
            {
                scanf("%d",&consthave[i]);
                sum+=consthave[i]*val[i];
                tol+=consthave[i];
            }
            sum-=p;
            if(sum<0)
            {
                printf("-1\n");
                continue;
            }
            int ans = INF;
            for(int i=0; i<2; i++)
            {
                for(int j=0; j<2; j++)
                {
                    memcpy(have,consthave,sizeof(consthave));
                    int t=sum;
                    if(i)
                    {
                        if(have[4])
                            t-=50,have[4]--;
                        else
                            continue;
                    }
                    if(j)
                    {
                        if(have[7])
                            t-=500,have[7]--;
                        else
                            continue;
                    }
                    if(t>=0)
                        ans=min(ans,solve(t)+i+j);
                }
            }
            if(ans==INF)
                printf("-1\n");
            else
                printf("%d\n",tol-ans);
        }
        return 0;
    }