Uva5211/POJ1873 The Fortified Forest 凸包

LINK

题意:给出点集,每个点有个价值v和长度l,问把其中几个点取掉,用这几个点的长度能把剩下的点围住,要求剩下的点价值和最大,拿掉的点最少且剩余长度最长。

思路:1999WF中的水题。考虑到其点的数量最多只有15个,那么可以使用暴力枚举所有取点情况,二进制压缩状态,预处理出该状态下的价值,同时记录该状态拥有的点,并按价值排序。按价值枚举状态,并对拥有的这些点求凸包,check是否合法,找到一组跳出即可。然而POJ似乎没有SPJ,同样的代码POJ会超时,UVA60ms,可以在常数上优化,不预处理,实时判价值最大值,不使用结构体等

/** @Date    : 2017-07-16 14:48:08
  * @FileName: POJ 1873 凸包.cpp
  * @Platform: Windows
  * @Author  : Lweleth (SoungEarlf@gmail.com)
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <utility>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <stack>
#include <queue>
#include <math.h>
//#include <bits/stdc++.h>
#define LL long long
#define PII pair<int ,int>
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;

struct point
{
	double x, y;
	point(){}
	point(double _x, double _y){x = _x, y = _y;}
	point operator -(const point &b) const
	{
		return point(x - b.x, y - b.y);
	}
	double operator *(const point &b) const 
	{
		return x * b.x + y * b.y;
	}
	double operator ^(const point &b) const
	{
		return x * b.y - y * b.x;
	}
};

double xmult(point p1, point p2, point p0)  
{  
    return (p1 - p0) ^ (p2 - p0);  
}  

double distc(point a, point b)
{
	return sqrt((double)((b - a) * (b - a)));
}

int sign(double x)
{
	if(fabs(x) < eps)
		return 0;
	if(x < 0)
		return -1;
	else 
		return 1;
}
////////////

point pt[50];
int v[50], l[50];
struct yuu
{
	point p[50];
	int val;
	int cnt;
	int len;
	int sta;
	double cst;
	void init(){cnt = len = val = cst = 0;}
}tt[1 << 16];

point stk[50];


/*int cmpA(point a, point b)//以p[0]基准 极角序排序
{
	int t = xmult(a, b, p[0]);
	if(t > 0)
		return 1;
	if(t == 0)
		return distc(a, p[0]) < distc(b, p[0]);
	if(t < 0)
		return 0;
}*/

int cmpB(yuu a, yuu b)//预处理用
{
	if(a.val == b.val)
		return a.cnt < b.cnt;
	return a.val < b.val;
}

int cmpC(point a, point b)//水平序排序
{
	return sign(a.x - b.x) < 0 || (sign(a.x - b.x) == 0 && sign(a.y - b.y) < 0);
}

/*void grahamS()
{
	while(!s.empty())
		s.pop();
	for(int i = 0; i < min(n, 2); i++)
		s.push(i);
	int t = 1;
	for(int i = 2; i < n; i++)
	{
		while(s.size() > 1)
		{
			int p2 = s.top();
			s.pop();
			int p1 = s.top();
			if(xmult(p[p1], p[p2], p[i]) > 0)
			{
				s.push(p2);
				break;
			} 
		}
		s.push(i);
	}
}*/

int graham(int st)//水平序
{
	sort(tt[st].p, tt[st].p + tt[st].cnt, cmpC);
	int top = 0;
	for(int i = 0; i < tt[st].cnt; i++)
	{
		while(top >= 2 && sign(xmult(stk[top - 2], stk[top - 1], tt[st].p[i])) <= 0)
			top--;
		stk[top++] = tt[st].p[i];
	}
	int tmp = top;
	for(int i = tt[st].cnt - 2; i >= 0; i--)
	{
		while(top > tmp && sign(xmult(stk[top - 2],stk[top - 1] ,tt[st].p[i] )) <= 0)
			top--;
		stk[top++] = tt[st].p[i];
	}
	if(tt[st].cnt > 1)
		top--;
	return top;
}

int check(int st)
{
	int ma = graham(st);
	double ans = 0;
	stk[ma] = stk[0];
	for(int i = 0; i < ma; i++)
		ans += distc(stk[i + 1], stk[i]);
	tt[st].cst = ans;
	if(sign(tt[st].len - ans) < 0)
		return 0;
	return 1;
}

int main()
{
	int n;
	int cc = 0;
	while(~scanf("%d", &n) && n)
	{
		if(cc)
			printf("
");
		cc++;
		double x, y;
		for(int i = 0; i < n; i++)
		{
			scanf("%lf%lf%d%d", &x, &y, v + i, l + i);
			pt[i] = point(x, y);
		}
		int c = 0;
		for(int st = 0; st < (1 << n); st++)//预处理
		{
			tt[st].sta = st;
			tt[st].init();
			c = 0;
			for(int i = 0; i < n; i++)
			{
				if(st & (1 << i))
					tt[st].len += l[i], tt[st].val += v[i];
				else 
					tt[st].p[c++] = pt[i];

			}
			tt[st].cnt = c;
		}
		sort(tt, tt + (1 << n), cmpB);

		//////
		for(int st = 0; st < (1 << n); st++)//遍历
		{
			if(check(st))
			{
				printf("Forest %d
", cc);
				printf("Cut these trees:");
				for(int i = 0; i < n; i++)
				{
					if(tt[st].sta & (1 << i))
						printf(" %d", i + 1);
				}
				printf("
Extra wood: %.2lf
", ((double)tt[st].len - tt[st].cst + eps));
				break;
			}
		}
	}
    return 0;
}
原文地址:https://www.cnblogs.com/Yumesenya/p/7211899.html