bzoj 1027 [JSOI2007]合金(计算几何+floyd最小环)

时间:2024-01-19 10:17:56

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]}即为最小环的点数。

【代码】

 #include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std; const int N = +;
const int INF = 1e9;
const double eps = 1e-; struct Pt {
double x,y;
Pt(double x=,double y=):x(x),y(y) {};
}; double cross(Pt a,Pt b,Pt c) {
return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
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); } int n,m,f[N][N];
Pt a[N],b[N]; int solve() {
FOR(i,,m) FOR(j,,m) {
bool flag=;
FOR(k,,n) {
double c=cross(b[k],a[i],a[j]);
if(c>eps || fabs(c)<eps && Dot(b[k],a[i],a[j])>eps) {
flag=; break;
}
}
if(flag) f[i][j]=; else f[i][j]=INF;
}
int ans=INF;
FOR(k,,m) FOR(i,,m) FOR(j,,m)
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
FOR(i,,m) ans=min(ans,f[i][i]);
if(ans==INF) return -;
else return ans;
} int main() {
scanf("%d%d",&m,&n);
double x;
FOR(i,,m) scanf("%lf%lf%lf",&a[i].x,&a[i].y,&x);
FOR(i,,n) scanf("%lf%lf%lf",&b[i].x,&b[i].y,&x);
printf("%d",solve());
return ;
}