貪心算法

  貪心算法是從問題的某一個初始狀態出發,經過逐步構造最優解的方法向給定目標前進,並指望經過這種方法產生出一個全局最優解的方法。html

  

  貪心算法的特色是貪心標準選擇最優子結構node

  貪心標準選擇:應用當前最好的標準做爲統一標準,將原問題變爲一個類似的但規模更小的子問題,以後的每一步選出來的必定是原問題最優解的一部分。若是一個問題貪心後只剩下一個子問題且有最優子結構時可使用貪心算法。c++

  最優子結構:當一個問題的最優解包含子問題的最優解時則此問題具備最優子結構性質。算法

  

  解題步驟:1.設計數據找規律;2.進行貪心猜測;3.正確性證實(列舉反例的通常證實和數學概括與反證法的嚴格證實);4.程序實現。數組

 

  第一題 NOIP2012 國王遊戲

  恰逢 HH國國慶,國王邀請nn 位大臣來玩一個有獎遊戲。首先,他讓每一個大臣在左、右手上面分別寫下一個整數,國王本身也在左、右手上各寫一個整數。而後,讓這 nn 位大臣排成一排,國王站在隊伍的最前面。排好隊後,全部的大臣都會得到國王獎賞的若干金幣,每位大臣得到的金幣數分別是:排在該大臣前面的全部人的左手上的數的乘積除以他本身右手上的數,而後向下取整獲得的結果。國王不但願某一個大臣得到特別多的獎賞,因此他想請你幫他從新安排一下隊伍的順序,使得得到獎賞最多的大臣,所獲獎賞儘量的少。注意,國王的位置始終在隊伍的最前面。函數

  輸入格式

  第一行包含一個整數nn,表示大臣的人數。spa

  第二行包含兩個整數 aa和 bb,之間用一個空格隔開,分別表示國王左手和右手上的整數。.net

  接下來 nn行,每行包含兩個整數aa 和 bb,之間用一個空格隔開,分別表示每一個大臣左手和右手上的整數。設計

  輸出格式rest

  一個整數,表示從新排列後的隊伍中獲獎賞最多的大臣所得到的金幣數。

  輸入輸出樣例

  輸入 
  
  1 1 
  2 3 
  7 4 
  4 6 
  輸出 
  2
 

  解題分析:相鄰兩我的交換對前面的人答案沒影響,對後面的人答案也沒影響,即相鄰兩人位置的交換隻會對這我的產生影響。所以能夠從這裏爲切入點,討論二元組順序對結果的影響。

  能夠設置這兩我的的位置分別爲i,i+1.左手數字爲a[i]、a[i+1],右手數字爲b[i]、b[i+1],兩人的金幣數爲w[i]、w[i+1]。

  設P[i]=a[1]*a[2]*a[3]*...*a[i]

  未調換順序時,k1=w[i]=P[i-1]/b[i],k2=w[i+1]=P[i]/b[i+1].ans1=max(k1,k2).

  調換順序後,k3=P[i-1]/b[i+1],k4=P[i-1]*a[i+1]/b[i],ans2=max(k3,k4).

  顯然有k1<k4,k3<k2.若是ans1<ans2那麼必有k2<k4.化簡能夠獲得a[i]*b[i]<a[i+1]*b[i+1],這代表若是把a[i],b[i]放在後面則會致使獲得的結果相比調換前會增長,因此爲了使ans取到最小值應該把a[i]*b[i]較小的放在前面,以a[i]*b[i]爲關鍵字排序。除了這部分貪心規則之外,還須要考慮大數相乘和大數相除的高精度算法處理.

  具體代碼以下:(難點在於高精度)

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 int n,tot,tot2,b[100005],ans[100005];
  5 
  6 struct node
  7 {
  8     int left,right;
  9 }a[1005];
 10 
 11 bool cmp(node x,node y)
 12 {
 13     return x.left * x.right < y.left * y.right;
 14 }
 15 
 16 void gjd(int o)
 17 {
 18     int c[100005] = {};
 19     int k = 0;
 20     int tot1 = 0;
 21     
 22     //將數組數據進行恢復爲十進制
 23     //模擬第i個大臣前的大數相除 
 24     for(int i = tot; i >= 1; i--)
 25     { 
 26         k = k * 10 + b[i];
 27         //減法模擬如k=52,r=15
 28         //第一次52-15=37
 29         //第二次37-15=22
 30         //第三層22-15=7
 31         //減法處理完後k=7,對應ci=3 
 32         //ci存放商,k存放餘數 
 33         while(k >= a[o].right)
 34         {
 35             c[i]++;
 36             k -= a[o].right;
 37         }
 38         if(c[i] && !tot1)
 39             tot1 = i;//tot1表示被除數的位數 
 40     }
 41     
 42     //tot2初始值爲0
 43     if(tot1 >= tot2)
 44     {
 45         int ok = 0;
 46         
 47         if(tot1 > tot2)
 48             ok = 1;
 49         else
 50         //比較大小 
 51             for(int i = tot1; i >= 1; i--)
 52             {
 53                 if(c[i] > ans[i])
 54                 {
 55                     ok = 1;
 56                     break;
 57                 }
 58                 if(c[i] < ans[i])
 59                 {
 60                     ok = -1;
 61                     break;
 62                 }
 63             }
 64             
 65         //tot1>tot2時ok=1 
 66         //將ci賦給ansi,tot2=tot1 
 67         if(ok)
 68         {
 69             for(int i = 1; i <= tot1; i++)
 70                 ans[i] = c[i];
 71             tot2 = tot1;
 72         }
 73         
 74         //大數相乘 
 75         int k = 0,j = tot + 5;
 76         for(int i = 1; i <= j; i++)
 77         {
 78              
 79             k += b[i] * a[o].left;
 80             b[i] = k % 10;
 81             k /= 10;
 82             if(b[i])
 83                 tot = i;//tot記錄大數相乘後位數 
 84         }
 85     }
 86 }
 87 
 88 
 89 int main(void)
 90 {
 91     scanf("%d",&n);
 92     for(int i = 0; i <= n; i++)
 93         scanf("%d%d",&a[i].left,&a[i].right);
 94         
 95     //貪心準則 對大臣ai*bi排序 
 96     sort(a+1,a+n+1,cmp);
 97     
 98     //國王左右手數字模擬 
 99     while(a[0].left)
100     {
101         b[++tot] = a[0].left % 10;
102         a[0].left /= 10;
103     }
104     
105     //大數乘除法 
106     for(int i = 1; i <= n; i++)
107         gjd(i);
108     for(int i = tot2; i >= 1; i--)
109         printf("%d",ans[i]);
110         
111     return 0;
112 } 

 

  如下代碼引用自https://blog.csdn.net/qq_35937273/article/details/83037021?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.control

 1 #include<bits/stdc++.h>
 2 using namespace std;  3 const int maxn=1010;  4 const int maxm=1000000;  5 struct data  6 {  7     int a,b;  8 } p[maxn];  9 int t[maxm];  ///第一位應該是所表示的大整數的位數也就是t[0],從第一位開始纔是整數的每一位 依次從小到大排列,也就是105在數組中表示成501
10 int d[maxm];  ///d數組是中間作儲存轉換的做用,第一位仍然是整數位數
11 int ans[maxm]; 12 int n; 13  
14 bool Comp(data x,data y) 15 { 16     return x.a*x.b<y.a*y.b; 17 } 18  
19 void Times(int *X,int v,int *Y)  ///高精度乘法 是從最低位開始的,能夠看作是模擬乘法運算
20 { 21     int len=X[0]; 22     for (int i=1; i<=len+20; i++) Y[i]=0; 23     for (int i=1; i<=len; i++) ///經過使x數組中的每一位與v相乘,%10,只取乘積的最後一位,/10加到下一位
24  { 25         Y[i]+=(X[i]*v); 26         Y[i+1]+=(Y[i]/10); 27         Y[i]%=10; 28  } 29     while (Y[len+1]>0) 30  { 31         len++; 32         Y[len+1]+=(Y[len]/10); 33         Y[len]%=10; 34  } 35     Y[0]=len; 36 } 37  
38 void Div(int *X,int v,int *Y)  ///高精度除法
39 { 40     int len=X[0]; 41     int rest=0; 42     for (int i=len; i>=1; i--) ///這裏注意:是從len開始的,也就是從整數的最大位開始的,能夠看作模擬除法運算
43  { 44         rest=rest*10+X[i]; 45         Y[i]=rest/v; 46         rest-=(v*Y[i]);  ///這裏至關因而除法當中的取餘數,和rest=rest*10+X[i]; 聯繫起來,就是一套完整的除法模擬
47  } 48     while (!Y[len]) len--;  ///這裏有點繞,例如 運算出來Y數組數7000,可實際結果只是7,這一步是去除0操做
49     if (!len) len=1;   ///假若結果就是0000,上一步會把全部的0都去除,len會變成了0,這裏就是避免這種狀況,使len=1
50     Y[0]=len; 51 } 52  
53 void Get_max(int *X,int *Y)   ///大整數的比較函數
54 { 55     if (Y[0]<X[0]) return;   ///先比較各自的位數,x[0],y[0]
56     if (Y[0]==X[0]) 57         for (int i=Y[0]; i>=1; i--) 58             if (Y[i]<X[i]) return; 59             else if (Y[i]>X[i]) break; 60     for (int i=0; i<=Y[0]; i++) X[i]=Y[i];  ///若Y大則把Y賦值給x
61 } 62  
63 int main() 64 { 65     scanf("%d",&n); 66     for (int i=0; i<=n; i++) scanf("%d%d",&p[i].a,&p[i].b); 67     sort(p+1,p+n+1,Comp); 68  
69     t[0]=1; 70     t[1]=1; 71     for (int i=1; i<=n; i++) 72  { 73         Times(t,p[i-1].a,d); 74         for (int j=0; j<=d[0]; j++) t[j]=d[j]; 75  Div(t,p[i].b,d); 76  Get_max(ans,d); 77  } 78     for (int i=ans[0]; i>=1; i--) 79         printf("%d",ans[i]); 80     printf("\n"); 81     return 0; 82 }
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息