题意
- 砍掉树把剩下的树围起来,要求花费最小。如果花费相同,求砍掉的树最少。
题解
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
int const N = 15 + 5;
double const inf = 1e10;
double const eps = 1e-8;
int n;
vector<int>ans,tmp;
struct Tree
{
double x,y,v,l;
}tree[N];
int dcmp(double x){
if(fabs(x) < eps) return 0;
else return x < 0 ? -1 : 1;
}
struct Point
{
double x,y;
Point(){};
Point(double x,double y):x(x),y(y){};
Point operator - (const Point& e)const{
return Point(x - e.x,y - e.y);
}
double operator ^ (const Point& e)const{
return x * e.y - y * e.x;
}
bool operator < (const Point& e)const{
return x < e.x || (x == e.x && y < e.y);
}
};
Point p1[N],p2[N],ch[N];
int convex(Point *p,int n,Point *ch){
sort(p,p+n);
int m = 0;
for(int i=0;i<n;i++){
while(m > 1 && ((ch[m-1] - ch[m-2]) ^ (p[i] - ch[m-2])) <= 0) m--;
ch[m++] = p[i];
}
int k = m;
for(int i=n-2;i>=0;i--){
while(m > k && ((ch[m-1] - ch[m-2]) ^ (p[i] - ch[m-2])) <= 0) m--;
ch[m++] = p[i];
}
if(n > 1) m--;
return m;
}
double dis(Point a,Point b){
return hypot(a.x - b.x,a.y - b.y);
}
double getlen(Point *p,int n){
double ans = 0;
for(int i=0;i<n;i++)
ans += dis(p[i],p[(i+1)%n]);
return ans;
}
int main(){
int caser = 0;
while(~scanf("%d",&n) && n){
for(int i=0;i<n;i++)
scanf("%lf%lf%lf%lf",&tree[i].x,&tree[i].y,&tree[i].v,&tree[i].l);
double minval = inf,extralen;
ans.clear();
for(int i=0;i<(1<<n);i++){ //状态压缩枚举砍掉的树
double val = 0,len1 = 0,len2 = 0;
int m1 = 0,m2 = 0;
tmp.clear();
for(int j=0;j<n;j++){
if(i & (1<<j)){
tmp.push_back(j);
val += tree[j].v;
len1 += tree[j].l; //能够围住的长度
}else
p2[m2++] = Point(tree[j].x,tree[j].y);
}
if(val > minval) continue; //加这一条件,否则超时
int num = convex(p2,m2,ch);
len2 = getlen(ch,num); //凸包的周长
if(dcmp(len1 - len2) < 0) continue;
if(dcmp(minval - val) > 0 || (!dcmp(minval - val) && m1 < ans.size())){
ans = tmp;
minval = val;
extralen = len1 - len2;
}
}
printf("Forest %d\n",++caser);
printf("Cut these trees: ");
for(int i=0;i<ans.size();i++) printf("%d ",ans[i] + 1);
printf("\n");
printf("Extra wood: %.2f\n",extralen);
printf("\n");
}
return 0;
}