子集枚举好题UVA1354

题目

分析:枚举子集以及关于该子集的补集,然后用子集去暴力构造一颗二叉树,注意左边的最远距离不一定来自于左子树,右边的最远距离也不一定来自于右子树

 1 #include "iostream"
 2 #include "cstdio"
 3 #include "cstring"
 4 #include "string"
 5 #include "vector"
 6 using namespace std;
 7 const int maxn=15;
 8 int T,s,vis[1<<maxn];
 9 double r,w[maxn],sum[1<<maxn];
10 struct Tree{
11     double L,R;
12     Tree():L(0),R(0){};
13 };
14 vector<Tree> tree[1<<maxn];
15
16 void dfs(int subset){
17     if(vis[subset])  return;
18     vis[subset]=1;
19     int flag=0;
20     for(int left=(subset-1)&subset;left;left=(left-1)&subset){
21         flag=1;
22         int right=left^subset;
23         double d1=sum[right]/sum[subset];
24         double d2=sum[left]/sum[subset];
25         dfs(left); dfs(right);
26         for(int i=0;i<tree[left].size();i++){
27             for(int j=0;j<tree[right].size();j++){
28                 Tree t;
29                 t.L=max(tree[left][i].L+d1,tree[right][j].L-d2);
30                 t.R=max(tree[left][i].R-d1,tree[right][j].R+d2);
31                 if(t.L+t.R<r)  tree[subset].push_back(t);
32             }
33         }
34     }
35     if(!flag)  tree[subset].push_back(Tree());
36 }
37 int main()
38 {
39     scanf("%d",&T);
40     while(T--){
41         scanf("%lf%d",&r,&s);
42         for(int i=0;i<s;i++)
43             cin>>w[i];
44         for(int i=0;i<1<<s;i++){
45             tree[i].clear();
46             sum[i]=0;
47             for(int j=0;j<s;j++){
48                 if(i&(1<<j)){
49                     sum[i]+=w[j];
50                 }
51             }
52         }
53         int root=(1<<s)-1;
54         memset(vis,0,sizeof(vis));
55         dfs(root);
56         double ans=-1;
57         for(int i=0;i<tree[root].size();i++)
58             ans=max(ans,tree[root][i].L+tree[root][i].R);
59         if(ans==-1)
60             printf("-1\n");
61         else
62             printf("%.10lf\n",ans);
63     }
64 }

时间: 2024-07-30 00:04:36

子集枚举好题UVA1354的相关文章

uva 11825 Hackers&amp;#39; Crackdown (状压dp,子集枚举)

题目链接:uva 11825 题意: 你是一个黑客,侵入了n台计算机(每台计算机有同样的n种服务),对每台计算机,你能够选择终止一项服务,则他与其相邻的这项服务都终止.你的目标是让很多其它的服务瘫痪(没有计算机有该项服务). 思路:(见大白70页,我的方程与大白不同) 把n个集合P1.P2.Pn分成尽量多的组,使得每组中全部集合的并集等于全集,这里的集合Pi是计算机i及其相邻计算机的集合,用cover[i]表示若干Pi的集合S中全部集合的并集,dp[s]表示子集s最多能够分成多少组,则 假设co

uva 11825 Hackers&#39; Crackdown (状压dp,子集枚举)

题目链接:uva 11825 题意: 你是一个黑客,侵入了n台计算机(每台计算机有相同的n种服务),对每台计算机,你可以选择终止一项服务,则他与其相邻的这项服务都终止.你的目标是让更多的服务瘫痪(没有计算机有该项服务). 思路:(见大白70页,我的方程与大白不同) 把n个集合P1.P2.Pn分成尽量多的组,使得每组中所有集合的并集等于全集,这里的集合Pi是计算机i及其相邻计算机的集合,用cover[i]表示若干Pi的集合S中所有集合的并集,dp[s]表示子集s最多可以分成多少组,则 如果cove

CodeForces 444C. DZY Loves Physics(枚举+水题)

转载请注明出处:http://blog.csdn.net/u012860063/article/details/37509207 题目链接:http://codeforces.com/contest/445/problem/C DZY Loves Physics DZY loves Physics, and he enjoys calculating density. Almost everything has density, even a graph. We define the densi

UVA 11205 The broken pedometer(子集枚举)

B - The broken pedometer Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Appoint description:  System Crawler  (2014-05-18) Description  The Broken Pedometer  The Problem A marathon runner uses a pedometer with wh

【最小生成树+子集枚举】Uva1151 Buy or Build

Description 平面上有n个点(1<=N<=1000),你的任务是让所有n个点连通,为此,你可以新建一些边,费用等于两个端点的欧几里得距离的平方. 另外还有q(0<=q<=8)个套餐,可以购买,如果你购买了第i个套餐,该套餐中的所有结点将变得相互连通,第i个套餐的花费为ci. 求最小花费. Solution 对于套餐可以用子集枚举处理,求最小生成树时只需考虑原图是最小生成树中的边. 正确性可以按Kruskal过程,以前被舍弃的边选了套餐后依然会被舍弃. Code 1 #in

动态规划之子集枚举

子集枚举DP P3959 宝藏 题目描述 参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了\(n\)个深埋在地下的宝藏屋, 也给出了这\(n\)个宝藏屋之间可供开发的\(m\)条道路和它们的长度. 小明决心亲自前往挖掘所有宝藏屋中的宝藏.但是,每个宝藏屋距离地面都很远, 也就是说,从地面打通一条到某个宝藏屋的道路是很困难的,而开发宝藏屋之间的道路 则相对容易很多. 小明的决心感动了考古挖掘的赞助商,赞助商决定免费赞助他打通一条从地面到某 个宝藏屋的通道,通往哪个宝藏屋则由小明来决定. 在此基础

UVA 1354 Mobile Computing(天平难题,枚举子集,递归,好题*)

1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 5 /** 6 思路:在每一个根节点枚举左右子树 7 8 学习: 9 (1)枚举子集的方法 例如 枚举 s = 100101 的子集 10 for(int l = (s-1)&s , l > 0 ; l = (l-1) & s){ 11 int r = s ^ l; 12 (2)思考:如何表示 左边距离 右边距离 . 该点的

UVa 725 - Division(枚举简单题)

今日无事,写篇日记.这是我写的第一道uva题(uva是算法竞赛入门经典里使用例题的题目来源),正值暑假,前几天看了书上中文题目和解析,玩了几日san11,又重拾起acm,今天晚上写了一下还是花了点时间. 题目:给你一个数字n,用0~9,10个数字组成两个五位数,使得他们的商为n,按顺序输出所有结果. 1.这里的除法不是c中的除(/)而是整除,一开始以为是整除,但那样79546 / 01283 = 62是一组解,79546+1 / 01283 = 62也是一组解了. 2.复杂度:枚举分子然后分子乘

子集枚举

#include <cstdio> #include <cstring> #include <vector> using namespace std; //枚举包含n个元素的集合中大小是k的子集 void subset_n_k(int n,int k){ int sub = 1; int end_state; for(int i= 1;i<k;i++){ sub<<=1; sub|=1; } end_state = sub<<(n-k);