[几何]森林

本文介绍了一个关于森林保护的问题,通过砍伐部分树木来构建凸包以保护剩余树木,同时使得砍伐树木的价值损失最小。使用深度优先搜索(DFS)结合Graham凸包算法求解最优解。

题目描述
森林里面有n棵贵重的树,你需要将它们保护起来。保护树木的方法是给它们做一个围栏(专业术语叫“凸包”),但围栏本身需要用这些树来做,因此需要砍下一些树。砍掉哪些树才能让损失的价值最小呢?如果有个解,取被砍掉的树的数目最小的一组。你可以认为在这样的限制下解是唯一的。

Input

输入文件forest.in的第一行表示一个正整数n(2<=n<=15),即树木的总数。以下n行每行四个0~10,000之间的整数x,y,v,l,表示树木的位置,价值和高度。各个树编号为1~n。

Output

输出文件forest.out的第一行表示最优解时浪费的长度(保留两位小数)。第二行以递增的顺序依次打印各个被砍掉的树编号。

分析
首先我们要明白这题没有说出来的重点
1、砍掉的树不算进凸包算法的点集中
2、一棵树不用保护(凸包长度为0)
3、两棵树所需长度是两者的曼哈顿距离的两倍(因为凸包是由开始点回到开始点的嘛)
然后就研究题目本身:
1、因为有“最优”这个字眼儿,所以可以推断不是DP就是搜索贪心啥的
-很快锁定在DFS上
2、题目都告诉你凸包和最优要求了还不会做?
-Graham算法,极角排序
3、重点:在Graham中不能直接排序原数组
-因为排序原数组会打乱原数组在深搜中的顺序
4、深搜结束条件别和最优判断混在一起,不好搞
-这是常识吧!

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
int n;
int tvalue,value,number[20],s,ts;
double length,tlength;
struct P
{
    int x,y,w,l,b;
}p[20],l[20];
int multi(P p1,P p2,P p0)
{
    return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
double dist(P p1,P p2)
{
    return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}
bool cmp(P a,P b)
{
    return multi(a,b,l[1])<0;
}
double graham()
{
    int i,j=0,top=0;
    double ass=0;
    P t,q[20];
    for (i=1;i<=n;i++)
    if (p[i].b==0)
    {
        j++;
        l[j]=p[i];
    }
    if (j==0)
    return 0;
    if  (j==1)
    return 0;
    if (j==2)
    return 2*dist(l[1],l[2]);
    for (i=2;i<=j;i++)
    if (l[1].x>l[i].x||l[1].x==l[i].x&&l[1].y>l[i].y)
    {
        t=l[1];l[1]=l[i];l[i]=t;
    }
    sort(l+2,l+j+1,cmp);
    l[j+1]=l[1];
    q[top]=l[1];
    top++;
    q[top]=l[2];
    top++;
    q[top]=l[3];
    for (i=4;i<=j+1;i++)
    {
        while (top>1&&multi(l[i],q[top],q[top-1])<0) top--;
        top++;q[top]=l[i];
    }
    for (i=0;i<top;i++)
    ass+=dist(q[i],q[i+1]);
    return ass;
}
void init()
{
    int i;
    scanf("%d",&n);
    for (i=1;i<=n;i++)
    scanf("%d%d%d%d",&p[i].x,&p[i].y,&p[i].w,&p[i].l);
    value=2147483647;
    s=2147483647;
}
void dfs(int dep)
{
    int i;
    if (dep>n)
    {
        double tb=graham();
        i=0;
        if ((tvalue==value&&ts<s||tvalue<value)&&tlength-tb>=0)
        {
            value=tvalue;
            length=tlength-tb;
            s=ts;
            for (int j=1;j<=n;j++)
            if (p[j].b)
            {
                i++;
                number[i]=j;
            }
        }
        return;
    }
    for (i=0;i<=1;i++)
    {
        p[dep].b=i;
        if (i==1)
        {
            tlength+=p[dep].l;
            tvalue+=p[dep].w;
            ts++;
        }
        dfs(dep+1);
        if (i==1)
        {
            tlength-=p[dep].l;
            tvalue-=p[dep].w;
            ts--;
        }
        p[dep].b=0;
    }
}
void print()
{
    int i;
    printf("%.2lf\n",length);
    for (i=1;i<=s;i++)
    printf("%d ",number[i]);
}
int main()
{
    init();
    dfs(1);
    print();
}
源码地址: https://pan.quark.cn/s/d1f41682e390 miyoubiAuto 米游社每日米游币自动化Python脚本(务必使用Python3) 8更新:更换cookie的获取地址 注意:禁止在B站、贴吧、或各大论坛大肆传播! 作者已退游,项目不维护了。 如果有能力的可以pr修复。 小引一波 推荐关注几个非常可爱有趣的女孩! 欢迎B站搜索: @嘉然今天吃什么 @向晚大魔王 @乃琳Queen @贝拉kira 第三方库 食用方法 下载源码 在Global.py中设置米游社Cookie 运行myb.py 本地第一次运行时会自动生产一个文件储存cookie,请勿删除 当前仅支持单个账号! 获取Cookie方法 浏览器无痕模式打开 http://user.mihoyo.com/ ,登录账号 按,打开,找到并点击 按刷新页面,按下图复制 Cookie: How to get mys cookie 当触发时,可尝试按关闭,然后再次刷新页面,最后复制 Cookie。 也可以使用另一种方法: 复制代码 浏览器无痕模式打开 http://user.mihoyo.com/ ,登录账号 按,打开,找到并点击 控制台粘贴代码并运行,获得类似的输出信息 部分即为所需复制的 Cookie,点击确定复制 部署方法--腾讯云函数版(推荐! ) 下载项目源码和压缩包 进入项目文件夹打开命令行执行以下命令 xxxxxxx为通过上面方式或取得米游社cookie 一定要用双引号包裹!! 例如: png 复制返回内容(包括括号) 例如: QQ截图20210505031552.png 登录腾讯云函数官网 选择函数服务-新建-自定义创建 函数名称随意-地区随意-运行环境Python3....
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值