東 華 大 學
《算法分析設計與綜合實踐》實驗報告
學生姓名:曹晨學號:171310402 指導教師:章昭輝
實驗時間:2019-4-9 實驗地點:圖文信息大樓三號機房
-
實驗名稱
貪心算法
-
實驗目的
- 理解貪心算法的概念。
- 掌握貪心算法的基本要素。
- 了解適用貪心算法的問題類型,並能設計相應的算法。
-
實驗內容
-
最優服務次序問題
問題描述:設有n個顧客同時等待一項服務,顧客i需要的服務時間為ti(1<=i<=n)。應如何安排n個顧客的服務次序才能使平均等待時間最小?平均等待時間是n個顧客等待服務時間的總和除以n。
算法設計:對於給定的n個顧客需要的服務時間,計算最優服務次序。
數據輸入:由文件input.txt提供輸入數據。第1行是正整數n,表示有n個顧客。接下來的1行中,有n個正整數,表示n個顧客需要服務的時間。
結果輸出:將計算的最小平均等待時間輸出到文件output.txt。
-
非單位時間任務安排問題
問題描述:具有截止時間和誤時懲罰的任務安排問題可描述如下
- 給定n個任務的集合S={1,2,….,n};
- 完成任務i需要ti時間,1<=i<=n;
- 任務i的截止時間di(1<=i<=n),即要求任務i在時間di之前結束
-
任務i的誤時時間wi(1<=i<=n),即任務i未在時間di之前結束,將招致wi的懲罰,若按時完成,則無懲罰。
任務安排要求確定一個S的時間表(最優時間表)使得總誤時懲罰達到最小
算法設計:對於給定的n個任務,計算總誤時懲罰最小的最優時間表
數據輸入:由文件input.txt給出輸入數據。第1行是一個正整數n,表示任務數。接下來的n行中,每行有3個正整數a、b、c,表示完成相應任務需要時間a,截止時間為b,誤時懲罰值為c。
結果輸出:將計算的總誤時時間輸出到文件output.txt。·
-
-
實驗過程
-
研究一個實例:有10個顧客,所需服務時間分別為56 12 1 99 1000 234 33 55 99 812
用t[i]來表示每個顧客所需的服務時間,T[i]表示等待的時間。假設已知一個最優服務次序A={t(1),t(2),…t(n)};按照此順序每個顧客的等待時間為:T(1)=t(1),T(2)=t(1)+t(2),…….,T(n)=t(1)+t(2)+….+t(n);總的等待時間為sum=T(1)+T(2)+….+T(n);可以看出t(1)被加了n次, t(2)被加了n-1次,依此類推,直到t(n)被加一次后結束,除以n就等於平均等待服務時間。運用貪心策略,即最短服務時間優先。將t[i]按照遞增的順序排序,所得的序列就是最優服務序列。
-
顧客編號 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
服務時間 |
1 |
12 |
33 |
55 |
56 |
99 |
99 |
234 |
812 |
1000 |
等待時間 |
1 |
13 |
46 |
101 |
157 |
256 |
355 |
589 |
1401 |
2401 |
算法描述:
1 //求最短平均等待時間的函數 2 int Findbest(int *t,int n)//n是顧客的個數,t[n]用來存放每個顧客所需的服務時間 3 { 4 sort(t,t+n);//從小到大遞增排列數組t 5 int sum=0;//總的等待時間初始化0 6 for(int i to n) 7 sum+=t[i]*(n-i);//從1到n遍歷最優服務次序,並加上各個等待服務時間 8 sum=sum/n;//求平均等待服務時間 9 return sum; 10 }
-
定義一個結構體Task包含三項數據。
struct Task
{
int a;//所需時間
int b;//截止時間
int c;//懲罰值
};
首先將任務按其截止時間遞增排序。假設對於任務1,2,…..,n,如果截至時間為d,則最小的誤時懲罰為p(i,d);
其中p(i,d)={p(i-1,d)+t[i].c,p(i-1,min(d,t[i].a))}
p(i-1,d)+t[i].c表示不做第i個任務時的誤時懲罰值,p(i-1,min(d,t[i].a))表示要做第i個任務時的誤時懲罰值,條件是必須在截止時間之前做完它。
對於第一個任務,如果時間小於它完成時間,那么遭受懲罰,否則的話做第一個任務
對於第i個任務,如果時間小於它的完成時間,不能執行,懲罰值等於上一個任務當前時間加上第i個任務的懲罰值,如果大於則比較不能完成時的懲罰值和完成這個任務所得的懲罰值,取二者最小的那個。下圖是一個實例的表。該例子為n=7;(1,4,70)(2,2,60)(1,4,50)(1,3,40)(1,1,30)(1,4,20)(3,6,80);
;
任務編號 |
截至時間0 |
1 |
2 |
3 |
4 |
5 |
6 |
0 |
30 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
90 |
60 |
30 |
30 |
30 |
30 |
30 |
2 |
130 |
90 |
60 |
30 |
30 |
30 |
30 |
3 |
200 |
130 |
90 |
60 |
30 |
30 |
30 |
4 |
250 |
180 |
130 |
90 |
60 |
60 |
60 |
5 |
270 |
200 |
150 |
110 |
80 |
80 |
80 |
6 |
350 |
280 |
230 |
190 |
160 |
150 |
110 |
算法描述:
1 //sort的自定義排序函數 2 bool comp(Task x,Task y) 3 { 4 if(x.b<y.b)//根據截至時間的大小進行非減排序 5 return true; 6 else return false; 7 } 8 //求最小懲罰值的函數 9 int Leastime(Task *t,int n)//t數組代表任務的三個參數,n代表任務的個數 10 { 11 sort(t,t+n,comp);//根據縮寫的comp函數排列數組(非減) 12 int d=t[n-1].b;//最大的截止時間d 13 int p[n][d+1];//二維數組p來代表p(i,d)時的最小懲罰數 14 memset(p,999,sizeof(p));//初始化數組 15 for(int i=0 to d)//遍歷二維數組的第一行,有時間做該任務,懲罰值為0,否則懲罰值為t[0].c 16 p[0][i]=(i>=t[0].a)?0:t[0].c; 17 for(int i=1 to n)//遍歷剩下的二維數組, 18 for(int j=0 to d) 19 p[i][j]=p[i-1][j]+t[i].c;//首先考慮不做當前任務的懲罰值 20 int h=t[i].b<j?t[0].b:j;//如果有時間做的話 21 if(h>=t[i].a&&p[i][j]>p[i-1][[h-t[i].a])//跟不做任務相比較 22 p[i][j]=p[i-1][h-t[i].a]//如果不做任務大於做任務的懲罰值,則做任務,改變p[i]j]的值 23 return p[n-1][d];//返回最小懲罰值 24 }
-
結果分析
-
答案是532
這道題非常的簡單,用到了貪心算法的思路,通過短短幾步就能求解出答案。
時間復雜度:一個for循環用來求總的等待服務時間
F(n)=n=O(n)
空間復雜度:一個一維數組t[n]用來存放各個顧客所需的服務時間
F(n)=n =O(n);
-
答案是110
這個題目是我覺得用動態規划的方法做出來的,因為有比較,做該任務和不做該任務的比較,貪心算法應該把兩種情況都寫入表中,但是只選了最優的方法
時間復雜度:
F(n)=n*logn+n*d=O(n*logn+n*d)
空間復雜度:用一維結構體數組分別來存放該任務的三個屬性,一個二維數組用來存放在截止時間為d,i個任務的最小懲罰值
F(n)=3*n+n*d=O(n+n*d);
-
- 實驗總結
附錄:(要求代碼里各行要有注釋)
見打包文件