你最愿意做的哪件事,才是你的天赋所在

0%

基础计算机和-凸包-poj1873

题目链接

poj1873

思路

观察到一共只有15个点,按位枚举就只有2e15种情况,然后需要特殊判断两种情况,第一种就是砍得只剩下一棵树或者没有得情况,那时候我们需要得长度为0,如果剩下两个树的话那么长度就为他们两个距离的两倍。剩下三棵或者大于三棵的情况,可以用凸包算法来计算最小周长。此处可以加快算法的地方就是,如果剩下树的价值小于当前已经得到的价值,那么就不用计算凸包了,就不可能是这种情况。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
#define ll long long
#define Vector Point
const double eps = 1e-12;
const int N = 1e4+10;
int syn(double x)
{
if(fabs(x)<eps)return 0;
if(x>0)return 1;
else return -1;
}
struct Point{
double x,y;
}p[N],s[N];
Vector operator - (Point a,Point b){return {b.x-a.x,b.y-a.y};}
double Cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;}
double dis(Point a,Point b){return sqrt((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y));}
bool cmp(Point p1,Point p2)
{
double tmp=(Cross(p[0]-p1,p[0]-p2));
if(tmp>0)return 1;
if(tmp==0&&(dis(p1,p[0])>dis(p2,p[0])))return true;
}
double getConvexHull(int n)
{
if(n==0)return 0;
for(int i=0;i<n;i++)
{
if(i!=0&&p[i].y<p[0].y)
{
swap(p[i],p[0]);
}
}
sort(p+1,p+n,cmp);
double ans = 0;
int tot = 0;
s[0]=p[0];
for(int i=1;i<n;i++)
{
while(tot>0&&Cross(s[tot]-s[tot-1],p[i]-s[tot])<=0)tot--;
tot++;
s[tot]=p[i];
}
s[tot+1]=p[0];
for(int i=0;i<=tot;i++)
ans+=dis(s[i],s[i+1]);
return ans;
}
struct tree{
double x,y;
int vi,li;
}t[20];
int main()
{
int n;
int cas = 1;
while(~scanf("%d",&n)!=EOF&&n!=0)
{
int ans,minn=999999;
int cuttreenum = 999999;
double remain;
for(int i=0;i<n;i++)scanf("%lf %lf %d %d",&t[i].x,&t[i].y,&t[i].vi,&t[i].li);
for(int i=0;i<(1<<n);i++)
{

double P = 0;
int val = 0;
int count = 0;
int cnt = 0;
int k = i;
for(int j=0;j<n;j++)
{
if(k&1)p[count++]={t[j].x,t[j].y};
else P+=t[j].li,val+=t[j].vi;
k>>=1;
}
double x;
if(val>minn)continue;
else if(count==1||count ==0)//如果只有一棵树的时候
{
x=0;
}
else if(count==2)
{
x=2*dis(p[0],p[1]);
}
else
x=getConvexHull(count);
if(syn(P-x)>=0)
{
if(syn(val-minn)<0){
minn=val;
ans=i;
remain=P-x;
cuttreenum=count;
}
if(syn(val-minn)==0)
{
if(cuttreenum>count)
{
minn=val;
ans=i;
remain=P-x;
cuttreenum=count;
}
}
}
}
printf("Forest %d\n",cas++);
printf("Cut these trees:");
for(int i=1;i<=n;i++)
{
if(ans%2==0)printf(" %d",i);
ans>>=1;
}
printf("\nExtra wood: %.2f\n\n",remain);
}
}
-------------你最愿意做的哪件事才是你的天赋所在-------------