poj 1873 The Fortified Forest (位运算枚举 + 凸包周长)

2024-03-28 12:48

本文主要是介绍poj 1873 The Fortified Forest (位运算枚举 + 凸包周长),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目链接:http://poj.org/problem?id=1873

大意:有一片N棵树的森林,要从中砍掉几棵树做成篱笆,把剩下的树围起来

输入:给N课树,每棵树的坐标是x,y,每棵树有一个vi和li分别代表砍掉这棵树的花费和砍掉后可做成篱笆的长度

输出:被砍掉树的编号(从1开始)、把剩下的树围起来后剩下的篱笆米数。


思路:暴力枚举..用01表示哪些树被砍了,维护一个可行的最小值,坑点是如果用%.2lf输出会wa,不知道是不是出现-0.00的原因,用%.2f过了,代码如下,欢迎指正:


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <stack>
#define INF 0x3fffffff
using namespace std;
struct point{int x,y;int vi,li;
}p0,p[16];int cross(int x1,int y1,int x2,int y2){return x2*y1 - x1*y2;
}
double dis(const point &a,const point &b){return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
bool cmp(const point &a,const point &b){int x1 = a.x - p0.x,y1 = a.y - p0.y;int x2 = b.x - p0.x,y2 = b.y - p0.y;if(cross(x1,y1,x2,y2) != 0)return cross(x1,y1,x2,y2) < 0;elsereturn dis(a,p0) < dis(b,p0);
}
//判断左旋还是右旋
bool ok(point p1,point p2,point p3){int x1 = p2.x - p1.x;int y1 = p2.y - p1.y;int x2 = p3.x - p2.x;int y2 = p3.y - p2.y;int c = cross(x1,y1,x2,y2);if(c <= 0) return true;else return false;
}
//计算周长
double GrahamScan(point px[],int N){//当森林中只有一颗或两棵树的时候if(N == 1) return 0;else if(N==2) return 2*dis(px[0],px[1]);//否则进行进行凸包计算求周长//凸包计算的方法推荐《算法艺术与信息学竞赛》(黑书)上P391页的相关介绍p0 = px[0];sort(px+1,px+N,cmp);stack<point> s;s.push(px[0]);s.push(px[1]);int i = 2;while(i < N ){point p2 = s.top();s.pop();point p1 = s.top();point p3 = px[i];if(ok(p1,p2,p3)){s.push(p2);s.push(px[i]);i++;}}//其实这里在上面可以写成N-1把最后一个点不进栈的。s.pop();double C = 0.0;point now = px[N-1];while(!s.empty()){C += dis(now,s.top());now = s.top();s.pop();}C += dis(px[0],px[N-1]);return C;
}
int main()
{int n,cas = 1;while(~scanf("%d",&n)&&n){for(int i=0;i<n;i++)scanf("%d%d%d%d",&p[i].x,&p[i].y,&p[i].vi,&p[i].li);int N = 1 << n;int ans_value = INF;int ans_cnt = 0;int ans_cutTrees[15];double ans_extra = 0.0;for(int bit=0;bit<N;bit++){int tmp_value = 0;double tmp_li = 0;int tmp_CutTrees[15],tmp_cnt = 0,not_cnt = 0;point notCut[15];for(int i =0;i<n;i++){// the trees have been cut downif(bit & (1 << i)){tmp_value += p[i].vi;tmp_li += (p[i].li*1.0);tmp_CutTrees[tmp_cnt++] = i;}else{//将最下、最右的点放在px[0],方便计算凸包if(notCut == 0){notCut[not_cnt++] = p[i];}else if(p[i].y < notCut[0].y || (p[i].y == notCut[0].y&&p[i].x < notCut[0].x)){notCut[not_cnt++] = notCut[0];notCut[0] = p[i];}else {notCut[not_cnt++] = p[i];}}}if((tmp_value >= ans_value  && ans_cnt <= tmp_cnt)|| tmp_value > ans_value) continue;double C = GrahamScan(notCut,not_cnt);if(C <= tmp_li){ans_value = tmp_value;ans_extra = tmp_li - C;ans_cnt = tmp_cnt;for(int i = 0;i<ans_cnt;i++)ans_cutTrees[i] = tmp_CutTrees[i];}}printf("Forest %d\n",cas++);printf("Cut these trees:");for(int i =0;i<ans_cnt;i++) printf(" %d",ans_cutTrees[i]+1);printf("\n");printf("Extra wood: %.2f\n\n",ans_extra);}return 0;
}


这篇关于poj 1873 The Fortified Forest (位运算枚举 + 凸包周长)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/855659

相关文章

WDF驱动开发-WDF总线枚举(一)

支持在总线驱动程序中进行 PnP 和电源管理 某些设备永久插入系统,而其他设备可以在系统运行时插入和拔出电源。 总线驱动 必须识别并报告连接到其总线的设备,并且他们必须发现并报告系统中设备的到达和离开情况。 总线驱动程序标识和报告的设备称为总线的 子设备。 标识和报告子设备的过程称为 总线枚举。 在总线枚举期间,总线驱动程序会为其子 设备创建设备对象 。  总线驱动程序本质上是同时处理总线枚

算法训练营第六十七天 | 卡码网110 字符串接龙、卡码网105 有向图的完全可达性、卡码网106 岛屿的周长

卡码网110 字符串接龙 这题一开始用的邻接表+dfs,不幸超时 #include <iostream>#include <list>#include <string>#include <vector>using namespace std;int minLen = 501;bool count(string a, string b) {int num = 0;for (int i

poj 3882(Stammering Aliens) 后缀数组 或者 hash

后缀数组:  构建后缀数组,注意要在字符串莫末尾加上一个没出现过的字符。然后可以2分或者直接扫描,直接扫描需要用单调队列来维护 VIEW CODE #include<cstdio>#include<algorithm>#include<iostream>#include<cmath>#include<queue>#include<stack>#include<string

poj 3294(Life Forms) 2分+ 后缀数组

我曾用字符串hash写,但是超时了。只能用后最数组了。大致思路:用不同的符号吧字符串连接起来,构建后缀数组,然后2分答案,依次扫描后缀数组,看是否瞒住条件。 VIEW CODE #include<cstdio>#include<vector>#include<cmath>#include<algorithm>#include<cstring>#include<cassert>#

poj 2391 Ombrophobic Bovines (网络流)

这是一道很经典的网络流的题目。首先我们考虑假如我们的时间为无穷大。我们吧每个点拆成2个点 i和i' .。虚拟源点s和汇点t。对于每个点建边(s,i, a[i])  (i‘,t,ib[i]) 。 其中a[i]为给点有多少牛,b[i]为容量。i和j连通 建边 (i,j',inf);如果最大流==所有牛的个数,就可能装下所有的牛。那么现在我们考虑时间。假设最大时间为T.那么如果i到j的的最短时间>T

poj 1330 LCA 最近公共祖先

水题目。直接上代码了。 VIEW CODE #include<cstdio>#include<algorithm>#include<iostream>#include<cmath>#include<queue>#include<stack>#include<string>#include<cstring>#include<map>#include<vector>#

poj 3160 Father Christmas flymouse 强连通+dp

首先我们可以确定的是,对于val值小于0的节点都变成0.   假设一个集合内2个房间都能任意到达,那么我就可以吧集合内的所有点的价值都取到,并且可以达到任一点。实际上集合内的每个点是相同的,这样的集合就是一个强连通分量。 那么我们就可以用tarjin算法进行强连通缩点, 最后形成一个dag的图。在dag的图上面进行dp。可以先用拓扑排序后dp。或者建反响边记忆化搜索 。 VIEW

运算放大器(运放)低通滤波反相放大器电路和积分器电路

低通滤波反相放大器电路 运放积分器电路请访问下行链接 运算放大器(运放)积分器电路 设计目标 输入ViMin输入ViMax输出VoMin输出VoMaxBW:fp电源Vee电源Vcc–0.1V0.1V–2V2V2kHz–2.5V2.5V 设计说明 这款可调式低通反相放大器电路可将信号电平放大 26dB 或 20V/V。R2 和 C1 可设置此电路的截止频率。此电路的频率响应与无源 RC 滤

无法解决 equal to 运算中 Chinese_PRC_90_CI_AS 和 Chinese_PRC_BIN 之间的排序规则冲突

这是因为数据库 oa 和 hh 的编码格式不一样导致的 select  groupname as oper_id,name as oper_name from security_users where name collate Chinese_PRC_CI_AS not in (select oper_name from PDA_UsersAndPWD )

IOS Swift 从入门到精通:数组,集合,元组,对比,字典,枚举

目录 数组 集合 元组 Arrays vs sets vs tuples 字典  字典默认值 创建空集合 枚举 枚举关联值 枚举原始值 复杂类型:总结 数组 数组是存储为单个值的值的集合。例如,John、Paul、George 和 Ringo 是姓名,但数组可让您将它们分组为单个值,即 The Beatles。 在代码中我们这样写: let john