1027: [JSOI2007]合金
Time Limit: 4 Sec Memory Limit: 162 MBSubmit: 2970 Solved: 787
[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
Sample Output
HINT
Source
【思路】
几何+最小环
第三维可以由前两维确定所以不用考虑。
两种原料可以合成的合金必在两点的线段上。推而广之,一堆点可以合成的合金一定在这堆点的凸包内。
于是题目变成了,求一个点数最少的多边形使得所有需要的合金都在该多边形内部。
对于两个点而言,如果所有点都在连线的一侧(这里视作左侧,边为有向边)或在边上则f[i][j]=1。
做一遍floyd,min{f[i][i]}即为最小环的点数。
【代码】
1 #include<cmath> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 6 using namespace std; 7 8 const int N = 500+10; 9 const int INF = 1e9; 10 const double eps = 1e-8; 11 12 struct Pt { 13 double x,y; 14 Pt(double x=0,double y=0):x(x),y(y) {}; 15 }; 16 17 double cross(Pt a,Pt b,Pt c) { 18 return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x); 19 } 20 double Dot(Pt a,Pt b,Pt c) { return (b.x-a.x)*(c.x-a.x)+(b.y-a.y)*(c.y-a.y); } 21 22 int n,m,f[N][N]; 23 Pt a[N],b[N]; 24 25 int solve() { 26 FOR(i,1,m) FOR(j,1,m) { 27 bool flag=1; 28 FOR(k,1,n) { 29 double c=cross(b[k],a[i],a[j]); 30 if(c>eps || fabs(c)<eps && Dot(b[k],a[i],a[j])>eps) { 31 flag=0; break; 32 } 33 } 34 if(flag) f[i][j]=1; else f[i][j]=INF; 35 } 36 int ans=INF; 37 FOR(k,1,m) FOR(i,1,m) FOR(j,1,m) 38 f[i][j]=min(f[i][j],f[i][k]+f[k][j]); 39 FOR(i,1,m) ans=min(ans,f[i][i]); 40 if(ans==INF) return -1; 41 else return ans; 42 } 43 44 int main() { 45 scanf("%d%d",&m,&n); 46 double x; 47 FOR(i,1,m) scanf("%lf%lf%lf",&a[i].x,&a[i].y,&x); 48 FOR(i,1,n) scanf("%lf%lf%lf",&b[i].x,&b[i].y,&x); 49 printf("%d",solve()); 50 return 0; 51 }