1027: [JSOI2007]合金

Time Limit: 4 Sec  Memory Limit: 162 MB
Submit: 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

10 10
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

5

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 }