UVA1354 Mobile Computing(DFS)

来源:互联网 发布:软件销售的税率 编辑:程序博客网 时间:2024/05/22 13:33

题目大意:给出房间宽度,重物个数n(n<=6)以及重物数量;每个天平的长度为一,每个天平的左右可以放重物或者另一个天平,要求在不超过房间宽度的情况下,使得天平尽量宽。


思路:显然的搜索题。由于重物的个数最多只有6个,因此我们可以状态压缩,用一个01串表示。然后暴力枚举左右天平的情况,用记忆化搜索。注意左臂为负数,右臂为正数

#include<cstdio>#include<vector>#include<cstring>#define MAXN 1<<6#define Max(a,b) a>b?a:b#define Min(a,b) a<b?a:busing namespace std;struct T{double llen;double rlen;T(){}T(double _llen,double _rlen){llen = _llen;rlen = _rlen;}};vector<T> a[MAXN];int n;double limit;double w[6],sum[MAXN];bool vis[1<<6];int bitcount(int x){int count = 0;while(x){if(x&1) count++;x >>= 1;}return count;}void dfs(int s){if(vis[s]) return;//已经枚举过vis[s] = 1;if(bitcount(s) == 1)//叶子节点{a[s].push_back(T(0,0));return;}for(int sl = (s - 1)&s; sl ; sl = (sl - 1)&s)//枚举左子树{int sr = s^sl;//右子树dfs(sl);dfs(sr);for(int i = 0; i < a[sl].size(); i++){for(int j = 0; j < a[sr].size(); j++){double tl = sum[sr]/(sum[sr] + sum[sl]);double tr = sum[sl]/(sum[sr] + sum[sl]);double ll = Min(-sum[sr]/(sum[sr] + sum[sl]) + a[sl][i].llen,sum[sl]/(sum[sr] + sum[sl]) + a[sr][j].llen);//比较 左臂+左子天平的左臂 与 右子天平的左臂-右臂  谁更小(左臂为负)double rr = Max(sum[sl]/(sum[sr] + sum[sl]) + a[sr][j].rlen,-sum[sr]/(sum[sr] + sum[sl]) + a[sl][i].rlen);//比较 右臂+右子天平的右臂 与 左子天平的右臂-左臂  谁更大(右臂为正)a[s].push_back(T(ll,rr));}}}}int main(){int T;scanf("%d",&T);while(T--){memset(vis,0,sizeof(vis));memset(a,0,sizeof(a));memset(sum,0,sizeof(sum));scanf("%lf%d",&limit,&n);for(int i = 0; i < n; i++)scanf("%lf",&w[i]);int len = 1<<n;for(int s = 0; s < len; s++){for(int i = 0; i < n; i++){if(s&(1<<i))sum[s] += w[i];}}double ans = -1;int s = (1<<n) - 1;dfs(s);for(int i = 0; i < a[s].size(); i++)// 预处理每种情况的重量{if(a[s][i].rlen - a[s][i].llen < limit){if(a[s][i].rlen - a[s][i].llen > ans){ans = a[s][i].rlen - a[s][i].llen;}}}if(ans == -1) printf("-1\n");else printf("%.16lf\n",ans);}}


0 0
原创粉丝点击