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
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 ;
}