大白书 1.1节 思维的体操

大白书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
单写

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值