poj1873(二进制枚举+求凸包周长)

题目链接:https://vjudge.net/problem/POJ-1873

题意:n个点(2<=n<=15),给出n个点的坐标(x,y)、价值v、做篱笆时的长度l,求选择哪些点来做篱笆围住另一些点,使得选出的这些点的价值和最小,如果价值和相等要求个数最小。

思路:

  看来这是WF的签到题吧。数据很小,直接二进制枚举 (1<<n),然后对未选出的点求凸包的周长,仅当选出点的长度l的和>=凸包周长时才更新答案。

AC code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;

const int maxn=20;
const int inf=0x3f3f3f3f;

struct Point{
    int x,y;
    Point():x(0),y(0){}
    Point(int x,int y):x(x),y(y){}
};

int n,cas,val,num,res[maxn],v[maxn],l[maxn],vis[maxn];
double ext;
int top,stack[maxn];
Point pt[maxn],list[maxn];

int cross(Point p0,Point p1,Point p2){
    return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}

double dis(Point p1,Point p2){
    return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
}

bool cmp(Point p1,Point p2){
    int tmp=cross(list[0],p1,p2);
    if(tmp>0) return true;
    else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
    else return false;
}

void init(int m){
    Point p0=list[0];
    int k=0;
    for(int i=1;i<m;++i){
        if((p0.y>list[i].y)||((p0.y==list[i].y)&&(p0.x>list[i].x))){
            p0=list[i];
            k=i;
        }
    }
    list[k]=list[0];
    list[0]=p0;
    sort(list+1,list+m,cmp);
}

double graham(int m){
    if(m==1){
        top=0;
        stack[0]=0;
    }
    else{
        top=1;
        stack[0]=0;
        stack[1]=1;
        for(int i=2;i<m;++i){
            while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) --top;
            stack[++top]=i;
        }
    }
    double ret=0;
    for(int i=0;i<top;++i)
        ret+=dis(list[stack[i]],list[stack[i+1]]);
    ret+=dis(list[stack[top]],list[stack[0]]);
    return ret;
}

int main(){
    while(scanf("%d",&n),n){
        val=num=inf;
        for(int i=0;i<n;++i)
            scanf("%d%d%d%d",&pt[i].x,&pt[i].y,&v[i],&l[i]);
        for(int i=1;i<(1<<n)-1;++i){
            int t1=0,t2=0,cnt=0;
            for(int j=0;j<n;++j){
                if((i>>j)&1){
                    t1+=v[j],t2+=l[j];
                }
                else{
                    list[cnt++]=pt[j];
                }
            }
            init(cnt);
            int cnt2=n-cnt;
            if((t1<val)||((t1==val)&&(cnt2<num))){
                double tmp=graham(cnt);
                if(tmp>t2) continue;
                val=t1,num=cnt2,ext=t2-tmp;
                int t=0;
                for(int j=0;j<n;++j){
                    if((i>>j)&1)
                        res[t++]=j;
                }
            }
        }
        printf("Forest %d\nCut these trees:",++cas);
        for(int i=0;i<num;++i)
            printf(" %d",res[i]+1);
        printf("\nExtra wood: %.2f\n\n",ext);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/FrankChen831X/p/11827130.html

时间: 2024-10-10 22:37:36

poj1873(二进制枚举+求凸包周长)的相关文章

poj1113Wall 求凸包周长 Graham扫描法

#include<iostream> #include<algorithm> #include<cmath> using namespace std; typedef pair<int ,int > ll; ll num,dot[1010]; int i; const double pi=3.1415926535898; ll operator -(ll a,ll b) { return make_pair(a.first-b.first,a.second-

POJ 1113 Wall(Graham求凸包周长)

题目链接 题意 : 求凸包周长+一个完整的圆周长. 因为走一圈,经过拐点时,所形成的扇形的内角和是360度,故一个完整的圆. 思路 : 求出凸包来,然后加上圆的周长 1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <cmath> 5 #include <algorithm> 6 7 const double PI = acos(-1.0) ;

Wall---hdu1348(求凸包周长 模板)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1348 求凸包周长+2*PI*L #include <stdio.h> #include <algorithm> #include <cstring> #include <cmath> using namespace std; const int N = 110; const double eps = 1e-6; const double PI = acos(-1

HDU 1392 Surround the Trees (Graham求凸包周长)

题目链接 题意 : 让你找出最小的凸包周长 . 思路 : 用Graham求出凸包,然后对每条边求长即可. Graham详解 1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <math.h> 5 #include <algorithm> 6 7 using namespace std ; 8 9 struct point 10 { 11 int

HDU 1392.Surround the Trees【凸包(求凸包周长)】【5月10】

Surround the Trees Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 9790    Accepted Submission(s): 3763 Problem Description There are a lot of trees in an area. A peasant wants to buy a rope to

凸包+二进制枚举——poj1873

注意剪枝一下,不然会t #include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<cmath> #include<algorithm> using namespace std; #define N 20 typedef double db; const db eps=1e-6; const db pi=acos(-1); int si

[codevs 1298] 凸包周长 [codevs 3201] 奶牛代理商 XI

题解: 今天开始学习计算几何. 这是一道计算几何求凸包周长的模板题,采用Andrew算法. 第二道题改下输出即可. 最后凸包周长的求法注意第一个点和最后一个点是同一个. 代码 100ms 3MB #include<cstdio> #include<cmath> #include<vector> #include<algorithm> using namespace std; const int maxn = 100000 + 10; int n; struc

LightOJ 1239 - Convex Fence 凸包周长

LINK 题意:类似POJ的宫殿围墙那道,只不过这道题数据稍微强了一点,有共线的情况 思路:求凸包周长加一个圆周长 /** @Date : 2017-07-20 15:46:44 * @FileName: LightOJ 1239 求凸包.cpp * @Platform: Windows * @Author : Lweleth ([email protected]) * @Link : https://github.com/ * @Version : $Id$ */ #include <stdi

HDU 1392 Surround the Trees (凸包周长)

题目链接:HDU 1392 Problem Description There are a lot of trees in an area. A peasant wants to buy a rope to surround all these trees. So at first he must know the minimal required length of the rope. However, he does not know how to calculate it. Can you