[BZOJ1027][JSOI2007]合金

来源:互联网 发布:宁夏领导干部网络培训 编辑:程序博客网 时间:2024/04/27 23:57

[JSOI2007]合金

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

Solution
首先前两维符合要求之后第三维自然符合,无视
两个材料能合成的所有合金在它们的连线的线段上
若干材料能合成的所有合金在它们的凸包内
那么我们要用最少的点构成的凸包囊括所有的要求点

枚举两个材料,如果所有合金在它们分割成的一个半平面里,就连一条有向边

然后就是最小环

Code

#include <bits/stdc++.h>using namespace std;#define rep(i, l, r) for (int i = (l); i <= (r); i++)#define per(i, r, l) for (int i = (r); i >= (l); i--)#define MS(_, __) memset(_, __, sizeof(__))#define MP make_pair#define PB push_backtypedef long long ll;typedef pair<int, int> PII;template<typename T> inline void read(T &x){    x = 0; T f = 1; char ch = getchar();    while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}    while (isdigit(ch))  {x = x * 10 + ch - '0'; ch = getchar();}    x *= f;}const int INF = 1e9;const double eps = 1e-8;struct Vec{    double x, y;    Vec() {}    Vec(double _x, double _y) : x(_x), y(_y) {}    inline double angle() const{ return atan2(y, x); }    inline double len() const{ return sqrt(x*x+y*y); }    inline Vec l_rot() const{ return Vec(-y, x); }    inline Vec r_rot() const{ return Vec(y, -x); }};inline Vec operator + (const Vec &a, const Vec &b) { return Vec(a.x+b.x, a.y+b.y); }inline Vec operator - (const Vec &a, const Vec &b) { return Vec(a.x-b.x, a.y-b.y); }template<typename T> inline Vec operator * (const Vec &a, T b) { return Vec(a.x*b, a.y*b); }template<typename T> inline Vec operator * (T a, const Vec &b) { return Vec(a*b.x, a*b.y); }template<typename T> inline Vec operator / (const Vec &a, T b) { return Vec(a.x/b, a.y/b); }inline double cross(const Vec &a, const Vec &b) { return a.x*b.y-a.y*b.x; }inline double dot(const Vec &a, const Vec &b) { return a.x*b.x+a.y*b.y; }typedef Vec Poi;inline bool le(double x, double y) { return x-y<=eps; }inline bool lt0(double x) { return x<-eps; }inline bool gt0(double x) { return x>eps;}inline bool eq0(double x) { return abs(x)<=eps; } inline bool between(Poi m, Poi l, Poi r) { return le(min(l.x,r.x),m.x)&&le(m.x,max(l.x,r.x)); }int n, m;Vec goal[510], given[510];int g[510][510];inline void spj(){    if (n == 1){ bool flag = true;        rep(i, 1, m) if (goal[i].x != given[1].x || goal[i].y != given[1].y) flag = false;        puts(flag ? "1" : "-1");        exit(0);    }}int main(){    read(n); read(m);    rep(i, 1, n) scanf("%lf%lf%*lf", &given[i].x, &given[i].y);    rep(i, 1, m) scanf("%lf%lf%*lf", &goal[i].x, &goal[i].y);    spj();    rep(i, 1, n) rep(j, 1, n) g[i][j] = INF;    rep(dot1, 1, n) rep(dot2, dot1+1, n){         Vec p = given[dot1]-given[dot2]; bool flag1 = false, flag2 = false, flag3 = false;        rep(dot3, 1, m){            double t = cross(p, goal[dot3]-given[dot2]);            if (lt0(t)) flag1 = true;            if (gt0(t)) flag2 = true;            if (eq0(t) && gt0(dot(goal[dot3]-given[dot2], goal[dot3]-given[dot1]))) flag3 = true;            if ((flag1 && flag2) || flag3) break;        }        if (flag1 && flag2) continue; if (flag3) continue;        if (flag1) g[dot1][dot2] = 1;         else if (flag2) g[dot2][dot1] = 1;        else g[dot1][dot2] = g[dot2][dot1] = 1;    }    int ans = INF;    rep(k, 1, n) rep(i, 1, n) rep(j, 1, n) g[i][j] = min(g[i][j], g[i][k]+g[k][j]);    rep(i, 1, n) ans = min(ans, g[i][i]);    if (ans > n) puts("-1"); else printf("%d\n", ans);    return 0;}
0 0
原创粉丝点击