计算几何/凸包/Floyd
Orz rausen大爷太强辣
计算几何题目果然不会做>_>
这个题……虽然他给了3个坐标,但实际上是个二维的计算几何题= =因为第三维坐标可以直接用前两维坐标表示出来。
考虑一下这些二维平面上的点的意义……
假如我们现在手里有一种原材料$(x_1,y_1)$,那么我们就只能搞出这一种合金= =
那么如果有两种原材料,我们配一配,就可以配出$(x_1,y_1)$到$(x_2,y_2)$这条线段上的所有合金= =
如果有三种,我们能配出的就是那个三角形区域的所有种类的合金……
以此类推……我们有n种原材料,我们能搞出的合金就是这n个点的凸包围出来的区域。
所以问题就变成了:从n个点中选出最少的p个点使得给定的m个点全部在这p个点的凸包内(主要意思是这样,当然还有一些边界情况,嗯就是共线、共点……)
这个是用floyd求最小环来做的……对于每对点(i,j),如果m个点都在向量(i->j)的左边,则连边 i->j 权值为1,那么$ans=min{dist[i][i]}$
P.S.好像没有用到求凸包的算法……不过用了凸包的思想……
1 /************************************************************** 2 Problem: 1027 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:1172 ms 7 Memory:2288 kb 8 ****************************************************************/ 9 10 //BZOJ 1027 11 #include<cmath> 12 #include<cstdio> 13 #include<cstring> 14 #include<cstdlib> 15 #include<iostream> 16 #include<algorithm> 17 #define rep(i,n) for(int i=0;i<n;++i) 18 #define F(i,j,n) for(int i=j;i<=n;++i) 19 #define D(i,j,n) for(int i=j;i>=n;--i) 20 using namespace std; 21 typedef long long LL; 22 inline int getint(){ 23 int r=1,v=0; char ch=getchar(); 24 for(;!isdigit(ch);ch=getchar()) if(ch=='-')r=-1; 25 for(; isdigit(ch);ch=getchar()) v=v*10+ch-'0'; 26 return r*v; 27 } 28 typedef double lf; 29 const lf eps=1e-8; 30 const int N=505,INF=1e9; 31 /*******************template********************/ 32 int n,m,d[N][N]; 33 struct Point{ 34 double x,y; 35 Point(){} 36 Point(lf x,lf y):x(x),y(y){} 37 void read(){scanf("%lf%lf%*lf",&x,&y);} 38 inline bool operator != (const Point &p)const{ 39 return fabs(x-p.x) > eps || fabs(y-p.y) > eps; 40 } 41 }a[N],b[N]; 42 typedef Point Vector; 43 Vector operator - (Point a,Point b){return Vector(a.x-b.x,a.y-b.y);} 44 lf Cross(Point a,Point b){return a.x*b.y-a.y*b.x;} 45 46 bool in_one_line(Point x,Point y){ 47 if (x.x > y.x) swap(x,y); 48 F(i,1,m) if (b[i].x < x.x || b[i].x > y.x) return 0; 49 if (x.y > y.y) swap(x,y); 50 F(i,1,m) if (b[i].y < x.y || b[i].y > y.y) return 0; 51 return 1; 52 } 53 int check(Point x,Point y){ 54 int cnt1=0,cnt2=0; lf tmp; 55 F(i,1,m){ 56 tmp=Cross(y-x,b[i]-x); 57 if (tmp>eps) ++cnt1; 58 if (tmp<-eps) ++cnt2; 59 if (cnt1 && cnt2) return 0; 60 } 61 if (!cnt1 && !cnt2 && in_one_line(x,y)){ 62 puts("2"); 63 return -1; 64 } 65 return cnt1 ? 1 : cnt2 ? 2 : 3; 66 } 67 void Floyd(){ 68 int ans=INF; 69 F(k,1,n) F(i,1,n) F(j,1,n) 70 d[i][j]=min(d[i][j],d[i][k]+d[k][j]); 71 F(i,1,n) ans=min(ans,d[i][i]); 72 if (ans==INF || ans<=2) puts("-1"); 73 else printf("%d ",ans); 74 } 75 void solve(){ 76 F(i,1,n) F(j,1,n) d[i][j]=INF; 77 F(i,1,n) F(j,i+1,n){ 78 int f=check(a[i],a[j]); 79 if (f==-1) return; 80 if (f==1) d[i][j]=1; 81 else if (f==2) d[j][i]=1; 82 else if (f==3) d[i][j]=d[j][i]=1; 83 } 84 Floyd(); 85 } 86 bool spj(){ 87 F(i,1,n) if (a[1]!=a[i]) return 0; 88 F(i,1,m) if (a[1]!=b[i]) return 0; 89 puts("1"); 90 return 1; 91 } 92 int main(){ 93 n=getint(); m=getint(); 94 F(i,1,n) a[i].read(); 95 F(i,1,m) b[i].read(); 96 if (spj()) return 0; 97 solve(); 98 return 0; 99 }
1027: [JSOI2007]合金
Time Limit: 4 Sec Memory Limit: 162 MBSubmit: 2423 Solved: 635
[Submit][Status][Discuss]
Description
某 公司加工一种由铁、铝、锡组成的合金。他们的工作很简单。首先进口一些铁铝锡合金原材料,不同种类的原材料中铁铝锡的比重不同。然后,将每种原材料取出一 定量,经过融解、混合,得到新的合金。新的合金的铁铝锡比重为用户所需要的比重。 现在,用户给出了n种他们需要的合金,以及每种合金中铁铝锡的比重。公司希望能够订购最少种类的原材料,并且使用这些原材料可以加工出用户需要的所有种类 的合金。
Input
第 一行两个整数m和n(m, n ≤ 500),分别表示原材料种数和用户需要的合金种数。第2到m + 1行,每行三个实数a, b, c(a, b, c ≥ 0 且 a + b + c = 1),分别表示铁铝锡在一种原材料中所占的比重。第m + 2到m + n + 1行,每行三个实数a, b, c(a, b, c ≥ 0 且 a + b + c = 1),分别表示铁铝锡在一种用户需要的合金中所占的比重。
Output
一个整数,表示最少需要的原材料种数。若无解,则输出–1。
Sample Input
0.1 0.2 0.7
0.2 0.3 0.5
0.3 0.4 0.3
0.4 0.5 0.1
0.5 0.1 0.4
0.6 0.2 0.2
0.7 0.3 0
0.8 0.1 0.1
0.9 0.1 0
1 0 0
0.1 0.2 0.7
0.2 0.3 0.5
0.3 0.4 0.3
0.4 0.5 0.1
0.5 0.1 0.4
0.6 0.2 0.2
0.7 0.3 0
0.8 0.1 0.1
0.9 0.1 0
1 0 0