【BZOJ】1027: [JSOI2007]合金(凸包+floyd)

http://www.lydsy.com/JudgeOnline/problem.php?id=1027

没special judge wa了一发好蛋疼...

首先这题大概和黑书上的差不多...由于知道任意两种材料就能得到第三种材料的含量,所以可以忽略第三种含量...

首先来看,如果有两种材料,那么能合成的材料一定在这个线段上,证明很简单...

假设材料A和B,要合成材料C,将他们材料的含量放到二维坐标系上(x轴为材料1,y轴为材料2)

假设用了a的A,则用了1-a的B,有

$$
\begin{align}
aX_A+(1-a)X_B=X_C \\
aY_A+(1-a)Y_B=Y_C \\
0<=a<=1 \\
\end{align}
$$

显然了吧...

然后考虑多个点,因为两两之间的点都是取得到的,那么这些两两之间的点又能连接起来,重复下去,显然最终可以取到的点是这个点集的凸包内的点..

//upd:wiki了一下...这个就是凸包的线性意义...

//即

$$S=\{\sum_{x_i \in X} t_ix_i | t_i \in [0, 1] \} $$

因此容易判断-1的情况(特判一个点取完所有和两个点的线段取完所有,要不然后边凸包会错...)

然后求最少的点形成凸包,很容易想到吧...我在课堂上也yy出来了...

凸包上的点如果所有该包围的点都在左边(右手方向),那么这两个点是可以连接与右手方向的剩余原凸包上的点形成凸包的...证明很简单...凸包上任意的点的子集都是凸包(当然空集除外..)...

然后我们对这些点对连边...找最小长度的环即可....如此弱的数据随便来floyd...

#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define rep(i, n) for(int i=0; i<(n); ++i)
#define for1(i,a,n) for(int i=(a);i<=(n);++i)
#define for2(i,a,n) for(int i=(a);i<(n);++i)
#define for3(i,a,n) for(int i=(a);i>=(n);--i)
#define for4(i,a,n) for(int i=(a);i>(n);--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define read(a) a=getint()
#define print(a) printf("%d", a)
#define dbg(x) cout << (#x) << " = " << (x) << endl
#define error(x) (!(x)?puts("error"):0)
#define rdm(x, i) for(int i=ihead[x]; i; i=e[i].next)
inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<‘0‘||c>‘9‘; c=getchar()) if(c==‘-‘) k=-1; for(; c>=‘0‘&&c<=‘9‘; c=getchar()) r=r*10+c-‘0‘; return k*r; }

const double eps=1e-6;
int dcmp(double x) { return abs(x)<eps?0:(x<0?-1:1); }
struct ipt { double x, y; ipt(double _x=0, double _y=0) : x(_x), y(_y) {} };
bool operator== (ipt &a, ipt &b) { return dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0; }
double icross(ipt &a, ipt &b, ipt &c) {
	static double x1, x2, y1, y2;
	x1=a.x-c.x; y1=a.y-c.y;
	x2=b.x-c.x; y2=b.y-c.y;
	return x1*y2-x2*y1;
}
double idot(ipt &a, ipt &b, ipt &c) {
	static double x1, x2, y1, y2;
	x1=a.x-c.x; y1=a.y-c.y;
	x2=b.x-c.x; y2=b.y-c.y;
	return x1*x2+y1*y2;
}
bool cmp(const ipt &a, const ipt &b) { return a.x==b.x?a.y<b.y:a.x<b.x; }
void tu(ipt *p, ipt *s, int n, int &top) {
	sort(p, p+n, cmp);
	top=-1;
	rep(i, n) {
		while(top>0 && dcmp(icross(p[i], s[top], s[top-1]))>=0) --top;
		s[++top]=p[i];
	}
	static int k;
	k=top;
	for3(i, n-2, 0) {
		while(top>k && dcmp(icross(p[i], s[top], s[top-1]))>=0) --top;
		s[++top]=p[i];
	}
	if(n>1) --top;
	++top;
}
bool PonS(ipt &a, ipt &p1, ipt &p2) { if(a==p1 || a==p2) return true; return dcmp(icross(a, p1, p2))==0 && dcmp(idot(p1, p2, a))<0; }

const int N=505, oo=~0u>>2;
int d[N][N], n, m, ans=oo;
ipt t[N], a[N], b[N];
bool checktu() {
	rep(i, n) rep(j, m) if(dcmp(icross(b[j], a[i], a[i+1]))<0) return 0;
	return 1;
}
bool check(ipt &x, ipt &y) {
	rep(i, m) if(dcmp(icross(b[i], x, y))<0) return 0;
	return 1;
}
bool spj() {
	int flag;
	rep(i, n) { flag=1; rep(j, m) if(!(a[i]==b[j])) { flag=0; break; } if(flag) { puts("1"); return 1; } }
	rep(i, n) for1(j, i+1, n-1) {
		flag=1;
		rep(k, m) if(!PonS(b[k], a[i], a[j])) { flag=0; break; }
		if(flag) { puts("2"); return 1; }
	}
	return 0;
}

int main() {
	read(n); read(m); double tt;
	rep(i, n) scanf("%lf%lf%lf", &t[i].x, &t[i].y, &tt);
	rep(i, m) scanf("%lf%lf%lf", &b[i].x, &b[i].y, &tt);
	tu(t, a, n, n); a[n]=a[0];
	if(!checktu()) { puts("-1"); return 0; }
	if(spj()) return 0;
	rep(i, n) rep(j, n) d[i][j]=oo;
	rep(i, n) rep(j, n) if(i!=j) { if(check(a[i], a[j])) d[i][j]=1; else if(j>i) break; }
	rep(k, n) rep(i, n) rep(j, n) d[i][j]=min(d[i][j], d[i][k]+d[k][j]);
	rep(i, n) ans=min(ans, d[i][i]);
	printf("%d\n", ans<=2?-1:ans);
	return 0;
}

  


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

HINT

Source

时间: 2024-08-02 03:06:07

【BZOJ】1027: [JSOI2007]合金(凸包+floyd)的相关文章

BZOJ 1027 JSOI2007 合金 计算几何+Floyd

题目大意:给定一些合金,选择最少的合金,使这些合金能够按比例合成要求的合金 首先这题的想法特别奇异 看这题干怎么会想到计算几何 并且计算几何又怎么会跟Floyd挂边 好强大 首先因为a+b+c=1 所以我们仅仅要得到a和b就可以 c=1-a-b 所以c能够不读入了 然后我们把每种原料抽象成一个点 可知两个点能合成的合金一定在两点连线的线段上 证明:设两个点为(x1,y1)和(x2,y2),新合成的合金为(ax1+bx2,ay2+by2) (a+b=1,a,b>0) 两点连线为(y-y1)/(x-

bzoj 1027[JSOI2007]合金 - floyd + 凸包

1027: [JSOI2007]合金 Time Limit: 4 Sec  Memory Limit: 162 MB Description 某公司加工一种由铁.铝.锡组成的合金.他们的工作很简单.首先进口一些铁铝锡合金原材料,不同种类的原材料中铁铝锡的比重不同.然后,将每种原材料取出一定量,经过融解.混合,得到新的合金.新的合金的铁铝锡比重为用户所需要的比重. 现在,用户给出了n种他们需要的合金,以及每种合金中铁铝锡的比重.公司希望能够订购最少种类的原材料,并且使用这些原材料可以加工出用户需要

[BZOJ 1027][JSOI2007]合金(计算几何+Floyd最小环)

Description 某公司加工一种由铁.铝.锡组成的合金.他们的工作很简单.首先进口一些铁铝锡合金原材料,不同种类的原材料中铁铝锡的比重不同.然后,将每种原材料取出一定量,经过融解.混合,得到新的合金.新的合金的铁铝锡比重为用户所需要的比重. 现在,用户给出了n种他们需要的合金,以及每种合金中铁铝锡的比重.公司希望能够订购最少种类的原材料,并且使用这些原材料可以加工出用户需要的所有种类的合金. Solution 今天考试T3的70分算法似乎是这道原题(然而我没做过QwQ) 思路值得学习一下(

【BZOJ 1027】 (凸包+floyd求最小环)

[题意] 某公司加工一种由铁.铝.锡组成的合金.他们的工作很简单.首先进口一些铁铝锡合金原材料,不同种类的原材料中铁铝锡的比重不同.然后,将每种原材料取出一定量,经过融解.混合,得到新的合金.新的合金的铁铝锡比重为用户所需要的比重. 现在,用户给出了n种他们需要的合金,以及每种合金中铁铝锡的比重.公司希望能够订购最少种类的原材料,并且使用这些原材料可以加工出用户需要的所有种类的合金. [分析] 只要考虑前两个物质的比例,因为加起来等于1. 如果你看过zoj3154,就会知道这题的模型,用二元组表

[bzoj 1027][JSOI2007]合金(解析几何+最小环)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1027 分析: 首先因为一个合金的和为1,所以考虑2个材料合金能否合成一个需求合金的时候,只要考虑前两个值就可以了. 我们如果把这两个值放到平面直角坐标系中,设两个材料合金坐标分别为(x,y)和(m,n),那么易得这两个材料合金可以合成的需求合金对应的点在(x,y)(m,n)两点之间的线段上.(高中数学向量的性质可以证) 那么问题就转化为了:平面上有m个材料合金点,n个需求合金点,要求

bzoj 1027: [JSOI2007]合金

由于总和一定所以看前两个即可,可以他们抽象成平面上的点,两个点能合出来的点在以两点为端点的线段上,三个点的在以三点为顶点的三角形内,... 所以预先处理那两个点的连线在所有被需要的点的一边,便把距离设为1,跑一遍最小环就行了. 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<

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 1027 合金(凸包-最小环)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1027 题意:三种合金的材料若干种.需求合金若干种.每种需求合金可以由材料合金混合得到.问最少需要多少种材料能够混合出所有需要的合金? 思路:对于两种材料合金ab,若能够得到需 求合金p,那么p必在线段ab上.这里由于三种合金的和为1,只要二维就够了,也就是是一个二维的问题.那么问题转化成,在平面上,找出最少的点包含所有 的需求合金对应的点(答案为1和2特判一下就行).两两枚举材料合金x

BZOJ 1027 合金

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