• poj 1873 The Fortified Forest 凸包+位运算枚举 world final 水题


    题目来源:

    http://poj.org/problem?id=1873

    题意:给出n棵树的坐标,树的高度和树的价值,从这些树中砍掉一些(整棵整棵的)做围栏把剩余的树围起来,使得消耗的树的价值最小。输出应砍掉哪里些树以及剩余的材料的长度。(如果砍掉的价值相同,则取砍掉数目少的)(2 <= n <= 15)。

    1:因为只有15棵树,用位运算枚举砍树情况就行了。

    2:枚举时注意剪枝 

    3:当剩下的点集处理凸包时m<=1 时特殊处理下

    代码如下:

    #include <iostream>
    #include <algorithm>
    #include <stdlib.h>
    #include <iostream>
    #include <stdio.h>
    #include <stack>
    #include <string>
    #include <string.h>
    #include <algorithm>
    #include <stdlib.h>
    #include <vector>
    #include <set>
    #include <math.h>
    #include <cmath>
    #include <map>
    #include <queue>
    using namespace std ;
    typedef long long LL;
    const int inf=0x7fffffff;
    const int N = 20;
    double EPS= 1e-10;
    double add(double a, double b)
    {
        if( fabs(a+b)< EPS * ( fabs(a)+fabs(b) ) )  return 0;
        return a+b;
    }
    struct Point{
        double x,y;
        int v,l;
        double dist(Point p){
            return sqrt( add( ( x-p.x)*(x-p.x) , (y-p.y)*(y-p.y) ) );
        }
    };
    // pop1*p0p2 > 0 左转
    double xmult(Point p1, Point p2, Point p0){
        return add( (p1.x-p0.x)*(p2.y-p0.y), -(p1.y-p0.y)*(p2.x-p0.x) );
    }
    Point List[N]; // 点集
    int top;  // 栈顶指针
    Point qs[N];
    Point p[N];
    bool operator<(Point a, Point b) // 按y轴值从小到大, y轴值相同时,x轴从小到大排列
    {
        if(a.y != b.y) return a.y< b.y;
        else  return a.x < b.x;
    }
    // 这种基于平面扫描法的graham扫描算法中, qs中存储的是起点然后回到起点qs[0]=qs[top]=起点
    double graham(int n)
    {
        sort(List,List+n);
        double sum=0;
        if(n==0 || n==1) return 0;  // 特殊处理下
        qs[0]=List[0];
        qs[1]=List[1];
        top=1;
        //构造凸包的下侧
        for(int i=2; i<n;i++){
            while(top>=1 && xmult( qs[top],List[i],qs[top-1] )<=0 )
                top--;
            qs[++top]=List[i];
        }
        //构造凸包的上侧
        qs[++top]=List[n-2];
        int len=top;
        for(int i=n-3 ;i>=0 ; i--){
            while(top>=len &&  xmult( qs[top],List[i],qs[top-1] )<=0 )
                top--;
            qs[++top]=List[i];
        }
        for(int i=0 ; i<top ; i++)
            sum+=qs[i].dist(qs[i+1]);
        return sum;
    }
    // 二进制枚举
    void solve(int n,int &min_val, int &cut_num, double &re_len, int &ans)
    {
        for(int bit=0; bit<(1<<n); bit++) // 二进制枚举
        {
            int t=0,cut_val=0;
            double cut_len=0 ;
            for(int i=0; i<n; i++){
                if(bit & (1<<i))
                {
                    cut_len+=p[i].l;
                    cut_val+=p[i].v;
                }
                else
                {
                    List[t].x=p[i].x;
                    List[t++].y=p[i].y;
                }
            }
            if(cut_val > min_val) continue; // 一个重要的剪枝
            double c=graham(t);
            if(cut_len >=c ) // 满足长度限制,也算个剪枝吧
            {
                if(cut_val < min_val || (cut_val== min_val &&  n-t < cut_num))
                {
                    min_val=cut_val;
                    cut_num=n-t;
                    ans=bit;
                    re_len=cut_len-c;
                }
            }
        }
    }
    int main()
    {
        int n,k=1;
        int flag=1;
        while(scanf("%d",&n),n)
        {
            if(!flag) {puts("");}
            flag=0;
            for(int i=0; i<n; i++)
                scanf("%lf%lf%d%d",&p[i].x,&p[i].y, &p[i].v, &p[i].l);
            int min_val=inf;
            int cut_num=inf;
            double re_len=0;
            int ans=0;
            solve(n,min_val,cut_num,re_len,ans);
            printf("Forest %d
    ",k++);
            printf("Cut these trees:");
            for(int i=0 ; i<n; i++){
                if(ans & (1<<i))
                    printf(" %d",i+1);
            }
            printf("
    Extra wood: %.2lf
    ",re_len);
        }
        return 0;
    }
  • 相关阅读:
    PHP语句、函数及字符串处理
    JAVA代码 运算符
    utf-8
    ascii码对照表
    什么是数组
    教你如何---构建良好的windows程序(初学者必看) (转)
    代码
    Android课程---Android Studio简单设置
    Android课程---Android Studio使用小技巧:提取方法代码片段
    Android课程---Android Studio的一些小技巧
  • 原文地址:https://www.cnblogs.com/zn505119020/p/3645851.html
Copyright © 2020-2023  润新知