惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Latest news
Latest news
T
Troy Hunt's Blog
V
Vulnerabilities – Threatpost
L
LINUX DO - 热门话题
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Simon Willison's Weblog
Simon Willison's Weblog
V
V2EX
博客园 - 司徒正美
B
Blog RSS Feed
AWS News Blog
AWS News Blog
MyScale Blog
MyScale Blog
Scott Helme
Scott Helme
Cisco Talos Blog
Cisco Talos Blog
Last Week in AI
Last Week in AI
NISL@THU
NISL@THU
博客园 - Franky
P
Proofpoint News Feed
博客园_首页
C
CERT Recently Published Vulnerability Notes
雷峰网
雷峰网
S
Schneier on Security
P
Proofpoint News Feed
Hugging Face - Blog
Hugging Face - Blog
G
GRAHAM CLULEY
博客园 - 三生石上(FineUI控件)
月光博客
月光博客
WordPress大学
WordPress大学
The Hacker News
The Hacker News
T
Threatpost
阮一峰的网络日志
阮一峰的网络日志
A
Arctic Wolf
Microsoft Azure Blog
Microsoft Azure Blog
T
The Exploit Database - CXSecurity.com
Engineering at Meta
Engineering at Meta
罗磊的独立博客
T
The Blog of Author Tim Ferriss
D
Darknet – Hacking Tools, Hacker News & Cyber Security
I
Intezer
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
K
Kaspersky official blog
SecWiki News
SecWiki News
云风的 BLOG
云风的 BLOG
美团技术团队
C
Cybersecurity and Infrastructure Security Agency CISA
博客园 - 【当耐特】
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Security Latest
Security Latest
C
Cyber Attacks, Cyber Crime and Cyber Security
B
Blog
S
Security Affairs

博客园 - woodfish

偏序集的Dilworth定理 XJOJ历经2个月终于完成啦~~ fork()调用的一个趣题 实现google那种输入框提示的功能 POJ 3691 安徽第二题 有限状态自动机+DP 哈尔滨赛区网络预选赛总结 [计算几何]点集中的点能组成多少个正方形 [计算几何]POJ 1375 点对圆的切线+线段重叠 [计算几何]POJ 1556 判断线段相交+Dijkstra [计算几何]POJ 1266 三角形的外接圆 圆的参数方程 POJ 1026 置换群 [计算几何]POJ 1031 计算点对多边形的偏转角度 [计算几何]POJ2079 求点集中面积最大的三角形 [计算几何]POJ3608 求2个不相交凸包的最短距离 [计算几何]凸包的旋转卡壳算法 C++禁止一个类被继承的技术 C与汇编的接口技术 计算位数的3种方法 避免使用条件分支
[计算几何] POJ 1873 暴力+凸包
woodfish · 2008-09-08 · via 博客园 - woodfish

http://acm.pku.edu.cn/JudgeOnline/problem?id=1873

题目大意是从一个点集中选出一些点,是这些点的长度之和能够把剩下的点围起来,并且没个点有个权值,要求最后的选出的点的权值之和最小,如果有多个最小的,要求选出的点数最小。

由于点集数很小,n<=15,很容易想到枚举,每个点有选与不选2中状态,有2^n选点方式,没枚举一个选点方式,对剩下的点进行Graham扫描求凸包,看能不能满足要求。总的复杂度是O(2^n*n*logn)

一下有一些可以用到的优化手段:

1.枚举大可不必用dfs生成,可以直接用一个二进制数来表示选点集合。

2.在枚举出一个集合后,不要每次都求凸包,如果当前集合的权值之和>目前求出的最优权值之和,那就根本不用再往下面算了。

3.不要用vector来保存答案,这样肯定会超时。

#include <stdio.h>
#include 
<math.h>const int MAXN=15;struct point {
    
double x, y;
} pp[MAXN
+1],p[MAXN+1],h[MAXN+1];
int v[MAXN+1],l[MAXN+1];
int ans[MAXN+1],an;double mydistance(const point& p1,const point& p2) {
    
return sqrt( (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}
double multiply(const point& sp,const point& ep,const point& op) {
    
return((sp.x-op.x)*(ep.y-op.y)-(ep.x-op.x)*(sp.y-op.y));
}
int partition(point a[],int p,int r) {
    
int i=p,j=r+1,k;
    
double ang,dis;
    point R,S;
    k
=(p+r)/2;
    R
=a[p];
    a[p]
=a[k];
    a[k]
=R;
    R
=a[p];
    dis
=mydistance(R,a[0]);
    
while(1) {
        
while(1) {
            
++i;
            
if(i>r) {
                i
=r;
                
break;
            }
            ang
=multiply(R,a[i],a[0]);
            
if(ang>0)
                
break;
            
else if(ang==0) {
                
if(mydistance(a[i],a[0])>dis)
                
break;
            }
        }
        
while(1) {
             
--j;
            
if(j<p) {
                j
=p;
                
break;
            }
            ang
=multiply(R,a[j],a[0]);
            
if(ang<0)
                
break;
            
else if(ang==0) {
                
if(mydistance(a[j],a[0])<dis)
                    
break;
            }
        }
        
if(i>=j)break;
        S
=a[i];
        a[i]
=a[j];
        a[j]
=S;
    }
    a[p]
=a[j];
    a[j]
=R;
    
return j;
}
void anglesort(point a[],int p,int r) {
   
if(p<r) {
      
int q=partition(a,p,r);
      anglesort(a,p,q
-1);
      anglesort(a,q
+1,r);
   }
}
//对PointSet求凸包,点数为n,凸包上的点保存在ch中,点数位len
void Graham_scan(point PointSet[],point ch[],int n,int &len) {
    
int i,k=0,top=2;
    point tmp;
    
for(i=1;i<n;i++)
        
if ( PointSet[i].x<PointSet[k].x ||
            (PointSet[i].x
==PointSet[k].x) && (PointSet[i].y<PointSet[k].y) )
               k
=i;
    tmp
=PointSet[0];
    PointSet[
0]=PointSet[k];
    PointSet[k]
=tmp;
    anglesort(PointSet,
1,n-1);
    
if(n<3) {
        len
=n;
        
for(int i=0;i<n;i++) ch[i]=PointSet[i];
        
return ;
    }
    ch[
0]=PointSet[0];
    ch[
1]=PointSet[1];
    ch[
2]=PointSet[2];
    
for (i=3;i<n;i++) {
        
while (multiply(PointSet[i],ch[top],ch[top-1])>=0) top--;
            ch[
++top]=PointSet[i];
    }
    len
=top+1;
}
int main() {
    
int n;
    
int cases=0;
    
while(scanf("%d",&n)!=EOF&&n) {
        cases
++;
        
for(int i=0;i<n;i++)
            scanf(
"%lf %lf %d %d",&pp[i].x,&pp[i].y,&v[i],&l[i]);
        
int minv=1<<30;
        
double ex=0;for(int mask=0;mask<(1<<n);mask++) {
            
int tot=0;
            
int nowv=0;
            
int nowl=0;for(int i=0;i<n;i++) {
                
if(mask&(1<<i)) {
                    nowv
+=v[i];
                    nowl
+=l[i];
                }
else{
                    p[tot].x
=pp[i].x;
                    p[tot].y
=pp[i].y;
                    tot
++;
                }
            }
            
if(nowv>minv) continue;
            
if(tot==0 || tot==n) continue;
            
int len=0;
            
double nl=0;
            Graham_scan(p,h,tot,len);
            
for(int i=0;i<len;i++)
                nl
+=mydistance(h[i],h[(i+1)%len]);
            
if(nl<=nowl) {
                
if(nowv<minv || (nowv==minv&&n-tot<an)) {
                    minv
=nowv;
                    an
=0;
                    
for(int i=0;i<n;i++if(mask&(1<<i)) ans[an++]=i+1;
                    ex
=nowl-nl;
                }
            }
        }
        
if(cases>1) printf("\n");
        printf(
"Forest %d\n",cases);
        printf(
"Cut these trees:");
        
for(int i=0;i<an;i++) printf(" %d",ans[i]);
        printf(
"\n");
        printf(
"Extra wood: %.2f\n",ex);
    }
    
return 0;
}