Problem
 【JSOI2007】合金
TimeLimit:4Sec
MemoryLimit:162MB
 Description
某公司加工一种由铁、铝、锡组成的合金。他们的工作很简单。首先进口一些铁铝锡合金原材料,不同种类的原材料中铁铝锡的比重不同。然后,将每种原材料取出一定量,经过融解、混合,得到新的合金。新的合金的铁铝锡比重为用户所需要的比重。 现在,用户给出了n种他们需要的合金,以及每种合金中铁铝锡的比重。公司希望能够订购最少种类的原材料,并且使用这些原材料可以加工出用户需要的所有种类的合金。
第一行两个整数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。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 | 10 100.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
标签:凸包 Floyed
 Solution
首先,给出的三个参数确定两个就能确定第三个,因此可以把参数缩减为两个。
考虑两种金属是否能造出第三种金属,若能造成,则第三种金属的两个参数必和这两种金属的参数成比例关系。
推广到用k种金属制造一种合金,若将这k种金属的两个参数作为横纵坐标描成点,那么合金所代表的点只要在这k个点形成的凸包内即可制造。
由此,题目转化为选出尽量少的点使得目标点都在选出点所构成的凸包内。
对于一个条有向线段,它能被选出到凸包上当且仅当所有目标点都在它的左侧。那么处理出所有这样的边后,我们就在点与点间连出了若干条边。我们需要尽量选尽量少的点,即选尽量少的边,使其构成凸包。这样直接跑Floyed后枚举起始点即可。
 Code
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 
 | #include <bits/stdc++.h>#define MAX_N 500
 #define EPS 1e-8
 #define INF 0x3f3f3f3f
 #define x first
 #define y second
 #define mp make_pair
 #define pdd pair<dnt,dnt>
 using namespace std;
 typedef double dnt;
 bool G[MAX_N+5][MAX_N+5];
 pdd p[MAX_N+5], c[MAX_N+5];
 int n, m, f[MAX_N+5][MAX_N+5];
 pdd vec(pdd s, pdd t) {return mp(t.x-s.x, t.y-s.y);}
 dnt dot(pdd a, pdd b) {return a.x*b.x+a.y*b.y;}
 dnt cross(pdd a, pdd b) {return a.x*b.y-a.y*b.x;}
 bool chk(pdd s, pdd t, pdd a) {
 dnt mul = cross(vec(a, s), vec(a, t));
 if (fabs(mul) <= EPS && dot(vec(a, s), vec(a, t)) <= EPS) return true;
 if (mul < -EPS) return true;	return false;
 }
 bool spj() {
 for (int i = 1; i <= n; i++) if (fabs(p[i].x-p[1].x) > EPS || fabs(p[i].y-p[1].y) > EPS) return false;
 for (int i = 1; i <= m; i++) if (fabs(c[i].x-p[1].x) > EPS || fabs(c[i].y-p[1].y) > EPS) return false;
 return true;
 }
 int Floyed() {
 int ret = INF;	memset(f, INF, sizeof f);
 for (int i = 1; i <= n; i++)
 for (int j = 1; j <= n; j++)
 if (G[i][j] && i^j) f[i][j] = 1;
 for (int k = 1; k <= n; k++) for (int i = 1; i <= n; i++)
 for (int j = 1; j <= n; j++) f[i][j] = min(f[i][j], f[i][k]+f[k][j]);
 for (int i = 1; i <= n; i++) ret = min(ret, f[i][i]);
 return spj() ? 1 : (ret == INF ? -1 : ret);
 }
 int main() {
 scanf("%d%d", &n, &m), memset(G, true, sizeof G);	dnt t;
 for (int i = 1; i <= n; i++) scanf("%lf%lf%lf", &p[i].x, &p[i].y, &t);
 for (int i = 1; i <= m; i++) scanf("%lf%lf%lf", &c[i].x, &c[i].y, &t);
 for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) if (i^j)
 for (int k = 1; k <= m && G[i][j]; k++) G[i][j] &= chk(p[i], p[j], c[k]);
 return printf("%d\n", Floyed()), 0;
 }
 
 |