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

相关文章

Java 枚举的常用技巧汇总

《Java枚举的常用技巧汇总》在Java中,枚举类型是一种特殊的数据类型,允许定义一组固定的常量,默认情况下,toString方法返回枚举常量的名称,本文提供了一个完整的代码示例,展示了如何在Jav... 目录一、枚举的基本概念1. 什么是枚举?2. 基本枚举示例3. 枚举的优势二、枚举的高级用法1. 枚举

Rust中的Option枚举快速入门教程

《Rust中的Option枚举快速入门教程》Rust中的Option枚举用于表示可能不存在的值,提供了多种方法来处理这些值,避免了空指针异常,文章介绍了Option的定义、常见方法、使用场景以及注意事... 目录引言Option介绍Option的常见方法Option使用场景场景一:函数返回可能不存在的值场景

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

poj 1511 Invitation Cards(spfa最短路)

题意是给你点与点之间的距离,求来回到点1的最短路中的边权和。 因为边很大,不能用原来的dijkstra什么的,所以用spfa来做。并且注意要用long long int 来存储。 稍微改了一下学长的模板。 stack stl 实现代码: #include<stdio.h>#include<stack>using namespace std;const int M

poj 3259 uva 558 Wormholes(bellman最短路负权回路判断)

poj 3259: 题意:John的农场里n块地,m条路连接两块地,w个虫洞,虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。 任务是求你会不会在从某块地出发后又回来,看到了离开之前的自己。 判断树中是否存在负权回路就ok了。 bellman代码: #include<stdio.h>const int MaxN = 501;//农场数const int

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

poj 1287 Networking(prim or kruscal最小生成树)

题意给你点与点间距离,求最小生成树。 注意点是,两点之间可能有不同的路,输入的时候选择最小的,和之前有道最短路WA的题目类似。 prim代码: #include<stdio.h>const int MaxN = 51;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int P;int prim(){bool vis[MaxN];

poj 2349 Arctic Network uva 10369(prim or kruscal最小生成树)

题目很麻烦,因为不熟悉最小生成树的算法调试了好久。 感觉网上的题目解释都没说得很清楚,不适合新手。自己写一个。 题意:给你点的坐标,然后两点间可以有两种方式来通信:第一种是卫星通信,第二种是无线电通信。 卫星通信:任何两个有卫星频道的点间都可以直接建立连接,与点间的距离无关; 无线电通信:两个点之间的距离不能超过D,无线电收发器的功率越大,D越大,越昂贵。 计算无线电收发器D