大白书1.1节
例题1 UVA 11292
排序后贪心,每条恶龙用当前剩下的能力值最小的骑士
源码:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXN = 20000 + 5;
int x[MAXN], y[MAXN];
int main()
{
int n, m;
while(scanf("%d%d", &n, &m) != EOF && n + m){
for(int i = 1 ; i <= n ; i++) scanf("%d", &x[i]);
for(int j = 1 ; j <= m ; j++) scanf("%d", &y[j]);
sort(x + 1, x + n + 1);
sort(y + 1, y + m + 1);
int u, v;
u = v = 1;
long long ans = 0;
while(u <= n){
while(v <= m && y[v] < x[u]) v++;
if(v > m) break;
ans += y[v];
u++, v++;
}
if(u > n) printf("%I64d\n", ans);
else printf("Loowater is doomed!\n");
}
return 0;
}
例题2 UVA 11729
由于总的交待任务时间一定,因此把执行时间放在最前面最优。
所以还是排序后贪心。
源码:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <string>
#include <iostream>
using namespace std;
const int MAXN = 10000 + 5;
struct D
{
int u, v;
}d[MAXN];
bool cmp(D a, D b)
{
return a.v > b.v;
}
int main()
{
int n;
int cas = 0;
while(scanf("%d", &n) != EOF && n){
for(int i = 0 ; i < n ; i++) scanf("%d%d", &d[i].u, &d[i].v);
sort(d, d + n, cmp);
int ans = 0;
int sum = 0;
for(int i = 0 ; i < n ; i++){
ans = max(ans, sum + d[i].u + d[i].v);
sum += d[i].u;
}
printf("Case %d: %d\n", ++cas, ans);
}
return 0;
}
例题3 UVA 11300
看的题解。
每个人设一个变量X[i]为他向左边交出的金币。
然后解方程所有的X[i]都可以用X[1]来表示(用每个人最终金币数相等来列方程)。表达出答案ans用X1表示的式子,发现是n个与X1有关的带绝对值的一次项,形如sum(|x1 - Ci|),然后猜想X1去所有C的中位数时有最小值。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
#define LL long long
const int MAXN = 1e6 + 5;
LL m[MAXN];
LL c[MAXN];
int main()
{
int n;
while(scanf("%d", &n) != EOF){
LL sum = 0;
for(int i = 0 ; i < n ; i++) scanf("%lld", &m[i]), sum += m[i];
LL ave = sum / n;
sum = 0;
for(int i = 0 ; i < n ; i++){
if(i == 0) c[i] = 0;
else{
sum += m[i] - ave;
c[i] = sum;
}
}
sort(c, c + n);
LL mark = c[n / 2];
LL ans = 0;
for(int i = 0 ; i < n ; i++){
ans += abs(c[i] - mark);
}
printf("%lld\n", ans);
}
return 0;
}
例题4 UVA 1138
建立一个这样的模型,在一个圆上,这n个点移动到新的(n+m)个点去。起点重合,移动的时候贪心移动,即移动到最近的点。如果有两个最近的点,则优先移动到坐标小的点。因为新的点比旧的点多所以这样移动一定不会产生“移动到同一个点的情况”。
然而为什么n个点与(n+m)个点的起点相同一定有最优?精确的证明是假设n个点的起点与(n+m)个点起点重合的时候,其余点假设分配时移动到左边新点a个,右边新点b个,则有a=b(否则绕一圈回来后起点分配不会重合)。假设起点顺时针移动一小部分d使得a=b+1,则相应的移动距离增加为d + (b + 1) * d - b * d > 0。
粗略的证明是起点不重合就没法算啦~
源码:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
#define LL long long
int main()
{
int n, m;
while(scanf("%d%d", &n, &m) != EOF){
int cnt = 1;
long long step = n;
long long now = n + m;
long long ans = 0;
while(cnt < n){
while(step + n <= now) step += n;
ans += min(step + n - now, now - step);
now += n + m;
cnt++;
}
double res = 1.0 * ans / (1.0 * n * n + 1.0 * m * n) * 10000;
printf("%.4f\n", res);
}
return 0;
}
例题5 UVA 10881
单写
例题6 UVA 1030
单写