[NOIP备考]随机化贪心解决动态规划问题(一星)
2015-10-27 16:12
316 查看
还记得上一篇我写的拔河的题解嘛?
上篇链接—->这里
输入描述 Input Description
数据的第1行是一个n,表示参加拔河比赛的总人数,n<=100,接下来的n行表示第1到第n个人的体重,每个人的体重都是整数(1<=weight<=450)。
100
90
200
对于一组普通序列,贪心就是在保证人数差在题目条件内的情况下尽可能的平衡两边的人数,这个贪心显然是不对的,但是他也有恰好正确的几率,对于这个题来说这个几率大约为0.1%,几率很小,但是每次贪心是ON,那么我们可不可以多次贪心取最优的呢?
答案是显然的,我们每次对序列随即排序,重排后得到一个乱序序列,然后我们对这个序列进行贪心处理,这一次得到正解的几率很小,那么我们就把重排次数扩大为100000次,进行10W次重排贪心,说不定就有一次得到了正解……这个几率有多少呢? %0.1 * 10W ≈ 100%!
经过实践验证,随机化贪心的正确性:
![](http://img.blog.csdn.net/20151027161101621)
交一次A一次……;
下面附上代码:
其实就是上次题解中的贪心加了个10W次随机排序。
上篇链接—->这里
题目描述 Description
一个学校举行拔河比赛,所有的人被分成了两组,每个人必须(且只能够)在其中的一组,要求两个组的人数相差不能超过1,且两个组内的所有人体重加起来尽可能地接近。输入描述 Input Description
数据的第1行是一个n,表示参加拔河比赛的总人数,n<=100,接下来的n行表示第1到第n个人的体重,每个人的体重都是整数(1<=weight<=450)。
输出描述 Output Description
包含两个整数:分别是两个组的所有人的体重和,用一个空格隔开。注意如果这两个数不相等,则请把小的放在前面输出。样例输入 Sample Input
3100
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次随机排序。
相关文章推荐
- C语言 二维数组动态分配和释放
- ChemDraw Std 14性价比最高版本,即将下架
- 判断
- [置顶] oracle表空间过大时候的处理
- 十六、变更管理; 十七、信息系统安全管理; 十八、项目风险管理
- 开发板与电脑连接局域网
- 面向对象第五次作业
- Android数据存储的5种方法
- opencv-第六章-霍夫变换
- MQTT学习笔记-Mosquitto的安装与启动
- 二分查找----第一种(相同元素返回不确定哪个)
- Android数据存储的5种方法
- 包 过程 函数
- rsync实现linux与windows数据同步
- Linux里如何查找文件内容
- android开发之使用上下文菜单
- linux centos python scrapy 环境配置
- react-native 添加 Toast 模块
- android开发之使用上下文菜单
- android开发之使用上下文菜单