POJ 1873 The Fortified Forest(二进制枚举+凸包)

题目链接:

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

题解:

学会了一个新的枚举方法。。二进制枚举。。然后凸包搞一搞就好了

AC代码:

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

struct node
{
    int x,y,v;
    double l;
}e[20], tubao[20];

vector<node> retree;
double templen;
int tempvalue,tempi;

bool cmp(node a, node b)
{
    if(a.x == b.x)return a.y < b.y;
    return a.x < b.x;
}

double dis(node a, node b)
{
    return sqrt(1.0* (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

int cross(node a, node b, node c)
{
    return (a.x - b.x) * (c.y - b.y) - (a.y - b.y) * (c.x - b.x);
}

double convex(int len)
{
    if(len == 1)
        return templen;
    if(len == 2)
        return templen - dis(retree[0],retree[1])*2;
    sort(retree.begin(), retree.end(), cmp);
    int m = 0;
    for(int i = 0; i < len; i++)
    {
        while(m > 1 && cross(tubao[m-2], tubao[m-1], retree[i]) <= 0)
            m--;
        tubao[m++] = retree[i];
    }
    int k = m;
    for(int i = len - 2; i >= 0; i--)
    {
        while(m > k && cross(tubao[m-2], tubao[m-1], retree[i]) <= 0)
            m--;
        tubao[m++] = retree[i];
    }
    if(len > 1)
        m--;
    double length = 0;
    for(int i = 1; i < m; i++)
    {
        length += dis(tubao[i-1],tubao[i]);
    }
    length += dis(tubao[m-1],tubao[0]);
    return templen - length;
}

int main()
{
    int t,cas = 1;
    while(~scanf("%d", &t))
    {
        if(t == 0)break;
        int ansvalue = 1 << 30;
        int ansi = 0,ansnum = 0;
        double anslen = 0;
        for(int i = 0; i < t; i++)
            scanf("%d%d%d%lf", &e[i].x, &e[i].y, &e[i].v, &e[i].l);
        for(int i = 1; i < (1 << t) - 1; i++)//全砍掉和全不砍掉没有意义,不用讨论
        {
            retree.clear();
            tempvalue = 0, templen = 0;
            for(int j = 0; j < t; j++)
            {
                if(i & (1 << j))
                {
                    templen += e[j].l;
                    tempvalue += e[j].v;
                }
                else
                {
                    retree.push_back(e[j]);
                }
            }
            if(tempvalue > ansvalue)continue;//大了就不用管了,直接走你
            double now = convex(retree.size());
            if(now >= 0)
            {
                if(tempvalue < ansvalue)
                {
                    ansvalue = tempvalue;
                    ansi = i;
                    ansnum = t - retree.size();
                    anslen = now;
                }
                else if(tempvalue == ansvalue && ansnum > t - retree.size())
                {
                    ansi = i;
                    ansnum = t - retree.size();
                    anslen = now;
                }
            }
        }
        printf("Forest %d\nCut these trees:",cas++);
        for(int i=0;i<t;i++)
            if( (1<<i) & ansi)  printf(" %d", i+1 );
        printf("\nExtra wood: %.2f\n\n",anslen);
    }

    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值