bzoj1027

1027: [JSOI2007]合金

Time Limit: 4 Sec  Memory Limit: 162 MB
Submit: 2671  Solved: 703
[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

题意:见分析

分析:我把n和m的意义相调转

即n代表原材料种数,m代表所需产品数

显然,第三维不需要,因为a+b+c==1,前两维确定即确定第三维

当n==2时,若一个产品可以通过这两种原材料组合而成那么一定有

materia1.a*k+materia2.a*(1-k) == product.a

materia1.b*k+materia2.b*(1-k) == product.b

等等,这个形式。。。如果把它们的a,b表示成二元组(a, b),那么。。。。

不就是说明如果把a当成横坐标,b当成纵坐标,

那么这两种原材料所能组成的产品一定在两端点为(materia1.a, materia1.b)(materia2.a, materia2.b)的线段上吗?

那么如果n == 3时,显然根据向量的加减,所能组成的产品一定在这三点围成的三角形里

当n==k时,同理,所能组成的产品一定在这几个点所围成的图形里(即这几个原材料的点所形成的凸包里)

但显然,构成凸包的最少点未必就是包住产品点的最少点数

那么我们探究一下,

我们逆时针看那个围住产品点的图形

并称一个由原材料点构成的 能围住产品点的 图形为合法图形

探究合法图形的边有什么性质

显然,如果一条边可能属于一个合法图形,那么所有的产品点都在它的一侧,我们假定都在这条边的逆时针方向

(因为我们使用叉积判断,所以要这样,注意,我们是逆时针看那个合法图形的)

所以首先我们要枚举任意两个原材料点,判断它们所连的边是否合法。。。

然后我们根据所有的合法边,尝试围成一个点数最少的合法图形

等等。。。。。如果我们把每条边的长度设为1,那么点数的多少不就是那个图形(环)的长度吗!?

不就是最小环吗?

对于最小环,我推荐一篇文章

http://www.cnblogs.com/Yz81128/archive/2012/08/15/2640940.html

我个人的理解:

一下见解不局限于本题,普适于所有有向图的最小环

每次在进行floyd的更新前(保证当前所有的最短路不包含k),算出环上的点最大为k(一定要有k)的最小的环

这样更新ans = min(ans, dis[i][j]+map[j][k]+map[k][i])

因为当前没有更新dis[i][j]所代表的最短路不包含k,如此便枚举出所有的 环上的点最大为k的环

然后再进行更新

当然由于本题的特殊性,并不需要完整的最小环算法

只需要求一遍点 i->点 i(就是回到自己)的最短路即可(同原来的floyd)

提供代码

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <cmath>
  5 #include <deque>
  6 #include <vector>
  7 #include <queue>
  8 #include <iostream>
  9 #include <algorithm>
 10 #include <map>
 11 #include <set>
 12 #include <ctime>
 13 using namespace std;
 14 typedef long long LL;
 15 typedef double DB;
 16 #define For(i, s, t) for(int i = (s); i <= (t); i++)
 17 #define Ford(i, s, t) for(int i = (s); i >= (t); i--)
 18 #define Rep(i, t) for(int i = (0); i < (t); i++)
 19 #define Repn(i, t) for(int i = ((t)-1); i >= (0); i--)
 20 #define rep(i, x, t) for(int i = (x); i < (t); i++)
 21 #define MIT (2147483647)
 22 #define INF (1000000001)
 23 #define MLL (1000000000000000001LL)
 24 #define sz(x) ((int) (x).size())
 25 #define clr(x, y) memset(x, y, sizeof(x))
 26 #define puf push_front
 27 #define pub push_back
 28 #define pof pop_front
 29 #define pob pop_back
 30 #define ft first
 31 #define sd second
 32 #define mk make_pair
 33 inline void SetIO(string Name) {
 34     string Input = Name+".in",
 35     Output = Name+".out";
 36     freopen(Input.c_str(), "r", stdin),
 37     freopen(Output.c_str(), "w", stdout);
 38 }
 39
 40 const int N = 510;
 41 const DB Eps = 1e-6;
 42 inline int Cmp(DB a, DB b) ;
 43 struct Point {
 44     DB x, y;
 45
 46     inline bool operator ==(const Point &A) const {
 47         if(!Cmp(x, A.x) && !Cmp(y, A.y)) return 1;
 48         return 0;
 49     }
 50 } A[N], B[N];
 51 int n, m;
 52 int Dp[N][N], Map[N][N];
 53
 54 inline void Input() {
 55     scanf("%d%d", &n, &m);
 56     DB c;
 57     For(i, 1, n) scanf("%lf%lf%lf", &A[i].x, &A[i].y, &c);
 58     For(i, 1, m) scanf("%lf%lf%lf", &B[i].x, &B[i].y, &c);
 59 }
 60
 61 inline int Cmp(DB a, DB b) {
 62     if(a < b-Eps) return -1;
 63     if(a > b+Eps) return 1;
 64     return 0;
 65 }
 66
 67 inline bool Cover(Point x) {
 68     For(i, 1, m)
 69         if(!(x == B[i])) return 0;
 70     return 1;
 71 }
 72
 73 inline void Exit(string Ans) {
 74     cout<<Ans<<"\n";
 75     exit(0);
 76 }
 77
 78 inline DB Multi(Point O, Point A, Point B) {
 79     return (A.x-O.x)*(B.y-O.y)-(A.y-O.y)*(B.x-O.x);
 80 }
 81
 82 inline bool Couple(Point O, Point A) {
 83     For(i, 1, m) {
 84         if(Cmp(Multi(O, A, B[i]), 0.0)) return 0;
 85         DB Left = O.x, Right = A.x, Up = O.y, Down = A.y;
 86         if(Left > Right) swap(Left, Right);
 87         if(Down > Up) swap(Up, Down);
 88         if(Cmp(B[i].x, Left) < 0 || Cmp(B[i].x, Right) > 0 ||
 89             Cmp(B[i].y, Down) < 0 || Cmp(B[i].y, Up) > 0) return 0;
 90     }
 91     return 1;
 92 }
 93
 94 inline bool Judge(Point O, Point A) {
 95     For(i, 1, m)
 96         if(Cmp(Multi(O, A, B[i]), 0.0) < 0) return 0;
 97     return 1;
 98 }
 99
100 inline void Solve() {
101     if(!m) Exit("0");
102     For(i, 1, n)
103         if(Cover(A[i])) Exit("1");
104     For(i, 1, n)
105         For(j, i+1, n)
106             if(Couple(A[i], A[j])) Exit("2");
107
108     For(i, 1, n)
109         For(j, 1, n) Dp[i][j] = Map[i][j] = 10000;
110     For(i, 1, n)
111         For(j, 1, n) {
112             if(i == j) continue;
113             if(Judge(A[i], A[j])) Dp[i][j] = Map[i][j] = 1;
114         }
115
116     int Ans = 10000;
117     For(k, 1, n) {
118         For(i, 1, k-1)
119             For(j, 1, k-1)
120                 Ans = min(Ans, Dp[i][j]+Map[j][k]+Map[k][i]);
121
122         For(i, 1, n)
123             For(j, 1, n)
124                 Dp[i][j] = min(Dp[i][j], Dp[i][k]+Dp[k][j]);
125     }
126
127     if(Ans > n) Ans = -1;
128     printf("%d\n", Ans);
129 }
130
131 int main() {
132     #ifndef ONLINE_JUDGE
133     SetIO("1027");
134     #endif
135     Input();
136     Solve();
137     return 0;
138 }

表示这题我原来想挫了,本来想先把原材料点搞个凸包,产品点搞个凸包,然后再用dp求原材料凸包上最少用多少

时间: 2024-08-09 10:43:55

bzoj1027的相关文章

bzoj1027【JSOI2007】合金

题目描述 某公司加工一种由铁.铝.锡组成的合金.他们的工作很简单.首先进口一些铁铝锡合金原材料,不同种类的原材料中铁铝锡的比重不同.然后,将每种原材料取出一定量,经过融解.混合,得到新的合金.新的合金的铁铝锡比重为用户所需要的比重. 现在,用户给出了n种他们需要的合金,以及每种合金中铁铝锡的比重.公司希望能够订购最少种类的原材料,并且使用这些原材料可以加工出用户需要的所有种类的合金. 输入格式 第一行两个整数m和n(m, n ≤ 500),分别表示原材料种数和用户需要的合金种数.第2到m + 1

[bzoj1027][JSOI2007]合金

来自FallDream的博客,未经允许,请勿转载,谢谢. 某公司加工一种由铁.铝.锡组成的合金.他们的工作很简单.首先进口一些铁铝锡合金原材料,不同种类的原材料中铁铝锡的比重不同.然后,将每种原材料取出一定量,经过融解.混合,得到新的合金.新的合金的铁铝锡比重为用户所需要的比重. 现在,用户给出了n种他们需要的合金,以及每种合金中铁铝锡的比重.公司希望能够订购最少种类的原材料,并且使用这些原材料可以加工出用户需要的所有种类的合金. n,m<=500 看到这道神题根本没头绪,只好看看题解. 因为三

bzoj千题计划123:bzoj1027: [JSOI2007]合金

http://www.lydsy.com/JudgeOnline/problem.php?id=1027 因为x+y+z=1,所以z=1-x-y 第三维可以忽略 将x,y 看做 平面上的点 简化问题: 若只有两种 材料,那么可以合成 两点线段 上的所有的点 推广到多种材料: 若 用户点 在 材料点 构成的 凸包内,则可以合成 所以题目转化为 求材料点 组成的 能包含所有用户点 的 最小环 用Floyd 枚举 每两对材料点,若所有用户点在 在线段的左侧或在线段上 则 f[i][j]=1 表示i到j

bzoj 1390: [Ceoi2008]Fence

Description 在一个大小为1000*1000的区域中,有n个固定点,m棵tree . 现在你要建一个围栏来保护tree,建它的费用为你选用的固定点的个数 *20和 你没有圈进围栏的tree*111. 现在希望这个值越小越好. 3<=N<=100. 1<=M<=100 Input 第一行给出n,m 下面开始n行,给出固定的坐标 下面开始m行,给出tree的坐标 Output 输出最小费用 根据题目设定的参数,凡是可以围住的点都要围住,同bzoj1027可以转为最小环 #in

[转载]hzwer的bzoj题单

counter: 664BZOJ1601 BZOJ1003 BZOJ1002 BZOJ1192 BZOJ1303 BZOJ1270 BZOJ3039 BZOJ1191 BZOJ1059 BZOJ1202 BZOJ1051 BZOJ1001 BZOJ1588 BZOJ1208 BZOJ1491 BZOJ1084 BZOJ1295 BZOJ3109 BZOJ1085 BZOJ1041 BZOJ1087 BZOJ3038 BZOJ1821 BZOJ1076 BZOJ2321 BZOJ1934 BZOJ

弗洛伊德Floyd求最小环

模板: #include<bits/stdc++.h> using namespace std; const int MAXN = 110; const int INF = 0xffffff0; int temp,Map[MAXN][MAXN],Dist[MAXN][MAXN],pre[MAXN][MAXN],ans[MAXN*3]; void Solve(int i,int j,int k) { temp = 0; //回溯,存储最小环 while(i != j) { ans[temp++]