凸包 poj 1873

我竟然A了 worldfinal 的水题

n<=15

所以可以列举每一种情况

状态压缩

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<stack>
#include<math.h>

using namespace std;

#define MAXN 20
#define INF 100000000
class point
{
public:
    int x,y,v,len;
    int operator ^(point b)
    {
       return x*b.y-y*b.x;
    }
    point operator -(point b)
    {
        point c;
        c.x=x-b.x;
        c.y=y-b.y;
        return c;
    }
}x[MAXN],res[MAXN],tur[MAXN];
int ans,cut_len,MIN_val,MIN_CNT;
double left;

double Dis(point p1,point p2)
{
    return sqrt(double((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)));
}
bool cmp(point a,point b)
{
    int tmp=((a-res[0])^(b-res[0]));
    if(tmp>0)
        return 1;
    if(tmp==0&&Dis(a,res[0])<Dis(b,res[0]))
        return 1;
    return 0;
}
stack<point>s;

double tubao(int num)
{

    if(num==0)//这3个特判
        return 0;
    if(num==1)
        return 0;
    if(num==2)
        return 2*Dis(res[0],res[1]);
    int k=0; //扫描法 凸包
    for(int i=1;i<num;i++)
        if(res[i].y<res[k].y)
            k=i;
        else if(res[i].y==res[k].y&&res[i].x<res[k].x)
            k=i;

    swap(res[0],res[k]);

    sort(res+1,res+num,cmp);
    while(!s.empty())
        s.pop();
    s.push(res[0]);
    s.push(res[1]);
    point a,b;

    for(int i=2;i<num;i++)
    {
        b=s.top();
        s.pop();
        a=s.top();
        while(s.size()>1&&((res[i]-b)^(b-a))>=0)
        {
            b=a;
            s.pop();
            a=s.top();
        }
        s.push(b);
        s.push(res[i]);
    }

    int len=0;
    while(!s.empty())
    {
        tur[len++]=s.top();
        s.pop();

    }
    double dis=0;
    for(int i=0;i<len-1;i++)
        dis+=Dis(tur[i],tur[i+1]);
    dis+=Dis(tur[len-1],tur[0]);
    return dis;
}
int main()
{
    int n,ca;
    ca=1;

    while(scanf("%d",&n)!=EOF&&n)
    {
        if(ca!=1)
            printf("\n");
        for(int i=0;i<n;i++)
            scanf("%d%d%d%d",&x[i].x,&x[i].y,&x[i].v,&x[i].len);
        int ed=1<<n;
        MIN_CNT=MIN_val=INF;
        for(int i=0;i<ed;i++)//列举每一种情况
        {
            int cnt=0,num=0,val=0;
            double cut=0;

            for(int j=0;j<n;j++)
                if(i&(1<<j))
                {
                    cnt++;
                    cut+=x[j].len;
                    val+=x[j].v;
                }
                else
                {
                    res[num++]=x[j];
                }

            double dis=tubao(num);

            if(dis>cut)
                continue;
            if(val<MIN_val||val==MIN_val&&cnt<MIN_CNT)//维护失去权值最小
            {
                ans=i;
                MIN_val=val;
                MIN_CNT=cnt;
                left=cut-dis;
            }

        }
        printf("Forest %d\n", ca++);
        printf("Cut these trees:");
        for(int i=0;i<n;i++)
            if(ans&(1<<i))
                printf(" %d",i+1);
        printf("\nExtra wood: %.2lf\n",left);
    }

    return 0;
}

 

posted on 2017-01-14 10:26  HelloWorld!--By-MJY  阅读(136)  评论(0编辑  收藏  举报

导航