程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> poj - 1873 - The Fortified Forest

poj - 1873 - The Fortified Forest

編輯:C++入門知識

 題意:給出n棵樹的坐標,樹的高度和樹的價值,從這些樹中砍掉一些(整棵整棵的)做圍欄把剩余的樹圍起來,使得消耗的樹的價值最小。輸出應砍掉哪裡些樹以及剩余的材料的長度。(如果砍掉的價值相同,則取砍掉數目少的)(2 <= n <= 15)

 

——>>用二進制映射枚舉每種砍樹的情況,對於每一種情況,求凸包,求凸包的周長,判斷。(這裡用G++提交)

注意:1、如果砍掉的價值相同,數目也相同,應砍編號小的樹;

2、最後輸出時用"%.2f",千萬別用"%.2lf",多一個l與少一個l區別大大的大!!!

#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;

const int maxn = 15 + 1;
const int INF = 1000000000;

struct Tree
{
    double x;
    double y;
    int v;
    int l;
    Tree(){}
    Tree(int xx, int yy):x(xx), y(yy){}
    bool operator < (const Tree& e) const
    {
        return x < e.x || (x == e.x && y < e.y);
    }
}t[maxn];

Tree operator - (Tree A, Tree B){return Tree(A.x - B.x, A.y - B.y);}

double Cross(Tree A, Tree B){return A.x * B.y - A.y * B.x;}
double Dis(Tree A, Tree B) {return hypot(A.x - B.x, A.y - B.y);}

int ConvexHull(Tree *p, int n, Tree* ch)        //求凸包
{
    sort(p, p + n);
    int m = 0;
    for(int i = 0; i < n; i++)
    {
        while(m > 1 && Cross(ch[m-1] - ch[m-2], p[i] - ch[m-2]) < 0) m--;
        ch[m++] = p[i];
    }
    int k = m;
    for(int i = n-2; i >= 0; i--)
    {
        while(m > k && Cross(ch[m-1] - ch[m-2], p[i] - ch[m-2]) < 0) m--;
        ch[m++] = p[i];
    }
    if(n > 1) m--;
    return m;
}

double Perimeter(Tree *ret, int m)
{
    double perimeter = 0;
    for(int i = 1; i < m; i++) perimeter += Dis(ret[i], ret[i-1]);
    perimeter += Dis(ret[0], ret[m-1]);
    return perimeter;
}

int main()
{
    int n, i, Case = 1, bit;
    while(scanf("%d", &n) == 1 && n)
    {
        for(i = 0; i < n; i++) scanf("%lf%lf%d%d", &t[i].x, &t[i].y, &t[i].v, &t[i].l);
        int min_val = INF;      //砍掉的最小價值
        int min_cnt = INF;      //砍掉的最小價值時砍掉的樹的數量
        double exc_len = 0;     //做好圍欄後剩余木材長度
        int ans = 0;        //砍掉的方法,二進制映射
        for(bit = 0; bit < (1<<n); bit++)     //枚舉每一種砍樹的方法
        {
            Tree buf[maxn], ret[2*maxn];      //buf緩沖,ret求凸包後的點組
            double cut_len = 0;        //這一種方法砍掉的樹的總長度
            int cut_val = 0;        //這一種方法砍掉的樹的總價值
            int cut_cnt;        //這一種方法砍掉的樹的總數量
            int m = 0;      //使用這一種方法後剩下的樹的數量
            for(i = 0; i < n; i++)      //掃描這種方法
            {
                if(bit&(1<<i))        //被砍掉的
                {
                    cut_len += t[i].l;
                    cut_val += t[i].v;
                }
                else        //剩下的
                {
                    buf[m].x = t[i].x;
                    buf[m++].y = t[i].y;
                }
            }
            if(cut_val > min_val) continue;
            cut_cnt = n - m;
            int cnt = ConvexHull(buf, m, ret);      //求凸包
            double perimeter = Perimeter(ret, cnt);     //凸包周長
            if(cut_len >= perimeter)      //砍掉的樹滿足長度要求
            {
                if(cut_val < min_val || (cut_val == min_val && cut_cnt < min_cnt))
                {
                    min_val = cut_val;
                    min_cnt = cut_cnt;
                    exc_len = cut_len - perimeter;
                    ans = bit;
                }
            }
        }
        if(Case > 1) printf("\n");
        printf("Forest %d\n", Case++);
        printf("Cut these trees:");
        for(i = 0; i < n; i++) if(ans&(1<<i)) printf(" %d", i+1);
        printf("\n");
        printf("Extra wood: %.2f\n", exc_len);
    }
    return 0;
}

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved