题目描述
森林里面有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();
}
本文介绍了一个关于森林保护的问题,通过砍伐部分树木来构建凸包以保护剩余树木,同时使得砍伐树木的价值损失最小。使用深度优先搜索(DFS)结合Graham凸包算法求解最优解。
952

被折叠的 条评论
为什么被折叠?



