您的位置:首页 > 其它

[NOIP备考]随机化贪心解决动态规划问题(一星)

2015-10-27 16:12 316 查看
还记得上一篇我写的拔河的题解嘛?

上篇链接—->这里

题目描述 Description

一个学校举行拔河比赛,所有的人被分成了两组,每个人必须(且只能够)在其中的一组,要求两个组的人数相差不能超过1,且两个组内的所有人体重加起来尽可能地接近。

输入描述 Input Description

数据的第1行是一个n,表示参加拔河比赛的总人数,n<=100,接下来的n行表示第1到第n个人的体重,每个人的体重都是整数(1<=weight<=450)。

输出描述 Output Description

包含两个整数:分别是两个组的所有人的体重和,用一个空格隔开。注意如果这两个数不相等,则请把小的放在前面输出。

样例输入 Sample Input

3

100

90

200

样例输出 Sample Output

190 200

题解:

上次我们被这个DP虐的死去活来,为这个脑洞的DP感到惊叹,但是现在,我们不用DP,就用贪心去A掉这个题,这可是对头疼DP的人的福音啊(比如说我……)。

对于一组普通序列,贪心就是在保证人数差在题目条件内的情况下尽可能的平衡两边的人数,这个贪心显然是不对的,但是他也有恰好正确的几率,对于这个题来说这个几率大约为0.1%,几率很小,但是每次贪心是ON,那么我们可不可以多次贪心取最优的呢?

答案是显然的,我们每次对序列随即排序,重排后得到一个乱序序列,然后我们对这个序列进行贪心处理,这一次得到正解的几率很小,那么我们就把重排次数扩大为100000次,进行10W次重排贪心,说不定就有一次得到了正解……这个几率有多少呢? %0.1 * 10W ≈ 100%!

经过实践验证,随机化贪心的正确性:




交一次A一次……;

下面附上代码:

[code]#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<cstdlib>
#define itn int
#define Endl endl
using namespace std;
typedef long long ll;
const int size = 1000010;
ll lans,rans,lp,rp;
int num[size],n;
void randomm()
{
    for(int i = 1;i <= n;i ++)
    {
        int p = rand()%n+1;
        swap(num[i],num[p]);
    }
}
ll llans,rrans,minc = 2 << 28;
int main()
{
    srand((unsigned)(clock()));
    scanf("%d",&n);
    for(int i = 1;i <= n;i ++)  scanf("%d",&num[i]);
//  sort(num+1,num+1+n);
    for(int i = 1;i <= 100000;i ++)
    {
        randomm();
        lans = (ll)(num
);
        rans = 0;
        lp = 1;
        rp = 0;
        for(int i = n-1;i > 0;i --)
        {
            if(lans > rans)
            {
                rans += (ll)(num[i]);
                rp ++;
                if(rp - lp - 1 == i - 1 || rp-lp == i-1)
                {
                    for(int j = i-1;j > 0;j --)
                    {
                        lans += (ll)(num[j]);
                    }
                    break;
                }
            }
            else
            {
                lans += (ll)(num[i]);
                lp ++;
                if(lp - rp - 1 == i - 1 || lp - rp == i - 1)
                {
                    for(int j = i-1;j > 0;j --)
                    {
                        rans += (ll)(num[j]);
                    }
                    break;
                }
            }
        }
        if(lans > rans) swap(lans,rans);
        if(rans-lans < minc)
        {
            llans = lans;
            rrans = rans;
            minc = rans-lans;
        }
    }
    printf("%lld %lld",llans,rrans);
    system("pause");
    return 0;
}
/*
20
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 190
*/


其实就是上次题解中的贪心加了个10W次随机排序。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: