zoukankan      html  css  js  c++  java
  • BZOJ 1027: [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

    3 2
    0.25 0.25 0.5
    0 0.6 0.5
    1 0 0
    0.7 0.1 0.2
    0.85 0.05 0.1
    

    Sample Output

    2
    

    题意

    给定m个原材料,每一个材料都有 3种元素的含量(x,y,z, 表示含量百分比 x+y+z = 1.0)
    现在给定 n种合金(依然是告诉你 3种元素的含量),需要求使用最小种类数的原材料,使得可以通过融化混合得到这n种合金


    其实挺简单的,但是非常巧妙。

    首先有$x+y+z=1 $这个条件,那么这样就等价于二维状态,因为z可以由x,y表示出来。然后发现,如果说一种合金能够被两种原料合成,定然在两种原料所在的点连线之间,那么被多种原料表示就是在所成凸包之内。证明详见ACoin:here。然后就是欢乐的floyed求最小环了。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef double DB;
    const int maxn = 500 + 10;
    const int INF = 0x3f3f3f3f;
    const DB eps = 1e-10;
    
    int dcmp(DB x) {
    	if(fabs(x) < eps) return 0;
    	return x < 0 ? -1 : 1;
    }
    
    struct Point {
    	DB x, y;
    	Point() {}
    	Point(DB x, DB y):x(x), y(y) {}
    	void read() {
    		scanf("%lf%lf", &x, &y);
    	}
    };
    typedef Point Vector;
    Vector operator - (const Point &a, const Point &b) {
    	return Vector(a.x - b.x, a.y - b.y);
    }
    DB cross(Vector a, Vector b) {
    	return a.x * b.y - a.y * b.x;
    }
    DB dot(Point a, Point b) {
    	return a.x*b.x + a.y*b.y;
    }
    bool on(Point p, Point a, Point b) {
    	return dcmp(cross(a - p, b - p)) == 0 && dcmp(dot(a - p, b - p)) <= 0;
    }
    bool onleft(Point p, Point a, Point b) {
    	return cross(p - a, b - a) > 0;
    }
    
    Point Akane[maxn], Ranma[maxn];
    int G[maxn][maxn], n, m;
    
    bool ok(Point a, Point b) {
    	for(int i = 1; i <= m; ++i) {
    		if(!(on(Ranma[i], a, b) || onleft(Ranma[i], a, b)))
    			return false;
    	}
    	return true;
    }
    bool same_pos(int i) {
    	for(int j = 1; j <= m; ++j) {
    		if(Akane[i].x != Ranma[j].x || Akane[i].y != Ranma[j].y) {
    			return false;
    		}
    	}
    	return true;
    }
    
    void solve() {
    	if(m == 0) {
    		puts("0");
    		return ;
    	}
    	for(int i = 1; i <= n; ++i) {
    		for(int j = 1; j <= n; ++j) if(j != i) {
    			if(ok(Akane[i], Akane[j])) {
    				G[i][j] = 1;
    			}
    		}
    	}
    	for(int i = 1; i <= n; ++i) {
    		if(same_pos(i)) {
    			puts("1");
    			return ;
    		}
    	}
    	for(int k = 1; k <= n; ++k)
    		for(int i = 1; i <= n; ++i)
    			for(int j = 1; j <= n; ++j)
    				G[i][j] = min(G[i][j], G[i][k] + G[k][j]);
    	int ans = INF;
    	for(int i = 1; i <= n; ++i) ans = min(ans, G[i][i]);
    	if(ans == INF) puts("-1");
    	else printf("%d
    ", ans);
    }
    
    int main() {
    	DB tmp;
    	while(scanf("%d%d", &n, &m) != EOF) {
    		for(int i = 1; i <= n; scanf("%lf", &tmp), ++i) Akane[i].read();
    		for(int i = 1; i <= m; scanf("%lf", &tmp), ++i) Ranma[i].read();
    		memset(G, INF, sizeof G);
    		solve();
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    攻防世界wp--web robots
    kubernetes二: kubernetes 重要组件安装和集群管理
    kibana配置页面跳转
    二进制安装的k8s添加新的node节点
    分布式和微服务的区别
    kubernetes一: 二进制安装k8s集群
    kibana导入导出dashborad
    elk 创建一个只读用户
    x-pack模式下修改es集群密码
    docker基础命令
  • 原文地址:https://www.cnblogs.com/hzf-sbit/p/3919724.html
Copyright © 2011-2022 走看看