ural 1144. The Emperor's Riddle
1144. The Emperor's Riddle
Time limit: 1.0 second
Memory limit: 4 MB
Memory limit: 4 MB
Background
In the olden times there was a young emperor who was the bravest, wisest, richest, most handsome in the whole world. He had proven himself in endless of battles, quests, and victories but his court was not happy because he had not appointed a queen yet. However, choosing a queen was not easy because of his high status and standard, the emperor wanted a girl not only beautiful but smart and kind as well. Lightning Knight - that was the young Emperor's name - sent his most trusted knights out to seek for a girl like that; and after a long time searching, the men brought back two of the most beautiful and intelligent girls in all the lands. They were two princess sisters from a faraway land. The older sister - Van Trinh - was mysterious and beautiful like the moon, while Thuy Linh - the younger one - was bright and lovely as the sun. They were both famous for being kind, gentle, and intelligent to their people, and as many girls before them, they both fell truly, madly, deeply in love with the handsome emperor at first sight.
Now, the Emperor had to face the hardest test of all: to pick just one in these two sisters to become his rightful and beloved queen and lay the world under her feet. After countless sleepless nights, the Emperor sought out a just solution. He thought of a riddle and announced to the two princesses and the court that he would marry the first one who bring the right answer to his desk.
Problem
At the same time with the above event, the Emperor had just won the most important battle to unite all the lands in the world. That was two good news in such a short time. Being the rich and generous emperor he was, the Emperor wanted to reward to all the brave and loyal generals with boxes of gold. The distribution was not easy and that's why he chose it as the riddle for Van Trinh and Thuy Linh. Centuries has passed since then, the Emperor and queen might have died and their romance might have been forgotten from our world, but the riddle still remains as one of the hardest tasks in the ancient books.
The Emperor wants to reward N boxes of gold to M generals. The i-th box has the value of Ai. Now the Emperor wants to give N boxes to M generals so that the difference of gold between the general who receives the most gold and the general who receives the least gold is as small as possible. Note: a general can receive more than one box, and he must receive the whole box (i.e.: not half or 1/3 of box).
Input
The 1st line contains three positive integers N, M and K (N ≤ 10000, M ≤ 1000 and N ≥ M). K is the maximum result that the emperor accepts. The 2nd line contains N positive integers 0 < A1, A2, …, AN ≤ 1000.
Output
The 1st line contains one integer which is the minimum difference your program can find. In the next M lines, the i-th line contains the index of boxes rewarded to the i-th general.
Sample
input | output |
---|---|
10 3 4 12 95 16 37 59 50 47 3 41 95 |
4 6 7 9 1 8 10 4 3 5 2 |
Problem Author: HNT
Tags: none
Difficulty: 1778
题意:把n个数分成m组,要使极差小于k,问其中一组方案。
分析:这是一道很不错的题。
一定要注意到,这题不需要求精确解。
首先有一个显而易见的贪心。
把数字从大到小排序,然后分给目前总和最小的组。
然而这个贪心只能求得较优解,在大多数情况下,无法求得满足极差小于k的解。
。。。。然而有一种很不错的方法叫做调整法。。。
首先,有一个经典问题:有两组数,要让它们两两配对,使得这些数对之和的极差最小,怎么配对?
显然是一组从大到小,一组从小到大匹配。
那么回到原题。
我们先随便将n个数分成m组。
然后将每组树再随机分成两组,记为A组,B组。
然后问题就变成了经典问题:有2组m个数,要让它们两两配对,是的这些数对之和极差最小。
我们利用这种思想将A组,B组重新分配。
根据那个经典问题的思想,新的分配方案不会比旧的分配方案要差。
所以我们不断进行这一过程,直到极差不超过k。
实际实现的过程当中,我们可以采用贪心与调整法相结合的方法,
因为调整法毕竟调整的速度比较慢,容易超时。
1 /** 2 Create By yzx - stupidboy 3 */ 4 #include <cstdio> 5 #include <cstring> 6 #include <cstdlib> 7 #include <cmath> 8 #include <deque> 9 #include <vector> 10 #include <queue> 11 #include <iostream> 12 #include <algorithm> 13 #include <map> 14 #include <set> 15 #include <ctime> 16 #include <iomanip> 17 using namespace std; 18 typedef long long LL; 19 typedef double DB; 20 #define MIT (2147483647) 21 #define INF (1000000001) 22 #define MLL (1000000000000000001LL) 23 #define sz(x) ((int) (x).size()) 24 #define clr(x, y) memset(x, y, sizeof(x)) 25 #define puf push_front 26 #define pub push_back 27 #define pof pop_front 28 #define pob pop_back 29 #define ft first 30 #define sd second 31 #define mk make_pair 32 33 inline int Getint() 34 { 35 int Ret = 0; 36 char Ch = ' '; 37 bool Flag = 0; 38 while(!(Ch >= '0' && Ch <= '9')) 39 { 40 if(Ch == '-') Flag ^= 1; 41 Ch = getchar(); 42 } 43 while(Ch >= '0' && Ch <= '9') 44 { 45 Ret = Ret * 10 + Ch - '0'; 46 Ch = getchar(); 47 } 48 return Flag ? -Ret : Ret; 49 } 50 51 const int N = 10010, M = 1010; 52 int n, m, k, arr[N]; 53 priority_queue<pair<int, int> > index, boxes; 54 int sum[M], belong[N], tag[N]; 55 int tmp[N]; 56 int type[2][M], ranks[M], to[M]; 57 58 inline void Input() 59 { 60 scanf("%d%d%d", &n, &m, &k); 61 for(int i = 1; i <= n; i++) scanf("%d", &arr[i]); 62 } 63 64 inline int Check() 65 { 66 for(int i = 1; i <= m; i++) sum[i] = 0; 67 for(int i = 1; i <= n; i++) sum[belong[i]] += arr[i]; 68 int mx = -INF, mn = INF; 69 for(int i = 1; i <= m; i++) 70 mx = max(mx, sum[i]), 71 mn = min(mn, sum[i]); 72 return (mx - mn) - k; 73 } 74 75 inline bool Compare(int t, int a, int b) 76 { 77 return type[t][a] < type[t][b]; 78 } 79 80 inline bool CmpUp(int a, int b) 81 { 82 return Compare(0, a, b); 83 } 84 85 inline bool CmpDown(int a, int b) 86 { 87 return Compare(1, b, a); 88 } 89 90 inline void Solve() 91 { 92 srand(time(0)); 93 //sort(arr + 1, arr + 1 + n, greater<int>() ); 94 for(int i = 1; i <= m; i++) index.push(mk(-sum[i], i)); 95 for(int i = 1; i <= n; i++) boxes.push(mk(arr[i], i)); 96 for(int i = 1; i <= n; i++) 97 { 98 int u = index.top().sd, v = boxes.top().sd; 99 index.pop(), boxes.pop(); 100 sum[u] += arr[v], belong[v] = u; 101 index.push(mk(-sum[u], u)); 102 } 103 104 int now; 105 while((now = Check()) > 0) 106 { 107 //printf("%d\n", now); 108 for(int i = 1; i <= n; i++) 109 tag[i] = rand() & 1; 110 111 for(int t = 0; t < 2; t++) 112 for(int i = 1; i <= m; i++) 113 type[t][i] = 0; 114 for(int i = 1; i <= n; i++) 115 type[tag[i]][belong[i]] += arr[i]; 116 117 for(int t = 0; t < 2; t++) 118 { 119 for(int i = 1; i <= m; i++) 120 ranks[i] = i; 121 if(t == 0) 122 sort(ranks + 1, ranks + 1 + m, CmpUp); 123 else sort(ranks + 1, ranks + 1 + m, CmpDown); 124 125 for(int i = 1; i <= m; i++) to[ranks[i]] = i; 126 for(int i = 1; i <= n; i++) 127 if(tag[i] == t) 128 tmp[i] = to[belong[i]]; 129 } 130 131 for(int i = 1; i <= n; i++) 132 belong[i] = tmp[i]; 133 } 134 135 int ans = Check() + k; 136 printf("%d\n", ans); 137 vector<int> answer[M]; 138 for(int i = 1; i <= n; i++) answer[belong[i]].pub(i); 139 for(int i = 1; i <= m; i++) 140 { 141 int length = sz(answer[i]); 142 for(int j = 0; j < length - 1; j++) 143 printf("%d ", answer[i][j]); 144 if(length) printf("%d\n", answer[i].back()); 145 /*int p = 0; 146 for(int j = 0; j < length - 1; j++) 147 { 148 printf("%d ", arr[answer[i][j]]); 149 p += arr[answer[i][j]]; 150 } 151 if(length) 152 { 153 printf("%d ", arr[answer[i].back()]); 154 p += arr[answer[i].back()]; 155 } 156 printf("%d\n", p);*/ 157 } 158 //sfor(int i = 1; i <= m; i++) printf("%d ", sum[i]); 159 } 160 161 int main() 162 { 163 freopen("a.in", "r", stdin); 164 freopen("a.out", "w", stdout); 165 Input(); 166 Solve(); 167 return 0; 168 }