贪心算法之经典题目---订票
题目:一票务办公室为音乐会售票,出售某一固定数量的连号票(简称套票)。购票订单以该套票中最小的座位号作为标志。由于不能满足所有订单,故而采用:若订单完全满足观众要求的票全价;若订单中至少一个座位与观众要求不同,则半价。现求怎样处理订单,才能使总收入最高。输入为套票里座位数量,订单数以及每个订单对应的座位号(最小的座位号为标志)。输出订单处理结果,即处理后的套票号码。(不要求顺序,且输入数据都符合要求,最小座位号为1,订单可以不被接受。)
解题思路:
采用贪心算法,3个步骤:
1) 试图分配尽可能多的全价套票。
逆序处理。按照座位号递减的次序来处理订单,只要可行就立马接受该订单。记为s1。
2) 调整s1以减少浪费。
正序处理。若要用订单p来代替p1,就要求p<p1,并且p mod L(L为套票座位数量)<p1 mod L。记为s2。
3) 用半价票填充空位。
剩余未被接受的订单全取半价票,填充s2中全价套票之间的空位。记为s3。
代码:
1 #include <fstream> 2 #include <fstream> 3 #include <iostream> 4 #include <cstdio> 5 #include <cstring> 6 #include <cmath> 7 #include <cstdlib> 8 #include <algorithm> 9 10 using namespace std; 11 12 #define ll long long 13 14 const int maxl=100;//座位数上限 15 const int nl=50;//订单数上限 16 int len,n;//套票座位长度,订单数 17 int nn[nl],tnn[nl]; 18 bool bn[nl]={}; 19 20 int main() 21 { 22 //freopen("D:\\input.in","r",stdin); 23 //freopen("D:\\output.out","w",stdout); 24 int tn,tc=0,tc2=0; 25 scanf("%d %d",&len,&n); 26 for(int i=0;i<n;i++) 27 scanf("%d",&nn[i]); 28 sort(nn,nn+n); 29 tn=nn[n-1]; 30 for(int i=n-1;i>=0;i--)//the first choose 31 { 32 if(nn[i]>tn) continue; 33 bn[i]=1; 34 tc++; 35 tn=nn[i]-len; 36 } 37 tn=1; 38 for(int i=0;i<n;i++)//the second choose 39 { 40 if(bn[i]) 41 { 42 tn=nn[i]+len; 43 continue; 44 } 45 if(nn[i]<tn) continue; 46 for(int j=i+1;j<n;j++) 47 { 48 if(!bn[j]) continue; 49 if(nn[j]>=nn[i]+len) 50 { 51 bn[i]=1; 52 tn=nn[i]+len; 53 break; 54 } 55 else 56 { 57 if((nn[i]-1)%len<(nn[j]-1)%len) 58 { 59 bn[i]=1; 60 bn[j]=0; 61 tn=nn[i]+len; 62 } 63 break; 64 } 65 } 66 } 67 tc=n-tc; 68 tn=1; 69 for(int i=0;i<n;i++)//the last choose 70 { 71 if(!bn[i]) continue; 72 while(tc2<tc&&tn+len<=nn[i]) 73 { 74 tnn[tc2]=tn; 75 tc2++; 76 tn+=len; 77 } 78 tn=nn[i]+len; 79 } 80 while(tc2<tc&&tn+len<=maxl+1) 81 { 82 tnn[tc2]=tn; 83 tc2++; 84 tn+=len; 85 } 86 for(int i=0;i<n;i++)//output 87 { 88 if(bn[i]) 89 printf("%d ",nn[i]); 90 } 91 for(int i=0;i<tc2;i++) 92 printf("%d ",tnn[i]); 93 printf("\n"); 94 return 0; 95 }