[JSOI2007]合金
来源:互联网 发布:网络平台金融整顿 编辑:程序博客网 时间:2024/04/28 04:11
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
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
首先,对于每一个合金,其实我们可以只用其中的两个金属的比率,剩下的那个用一减就可以了。
然后,就可以在一个二维坐标中用点表示出所有提供的金属了。
这样,可以发现,多个点围成的凸包内部(包括边界)的任意点所表示的合金都是可以合成的了(可以从一条线证明起,再用三角形,至于多边形中,对于每个点都必然回落在边上三点所围成的三角形内,就简化成三边)。
所以,只要找到几个点围成一个凸包(至于为什么一定是凸包。。。很明显),包括所有需要的金属点,那么,最少点数的凸包的点数即为所求。注意,凸包有可能是一条直线,或只有一个点。
那么,对于任意一条边,只要满足所有需要的金属都在他一侧,就有可能在结果凸包上。所以,对于所有这样的边都连一条权为一的边,然后跑一遍最小环即可。
最小环:
for(intk=0;k<nVertex;++k){
}
方法就是找到最小环上编号最大的点,最小环就是编号最大的点与其他两个点的连边再加上那两个点之间的最短路。Floyd最外层循环为k,即为枚举中间节点,在跑最短路之前,枚举i,j。
则:ans:=min(ans,dist[i][j]+graph[j][k]+graph[k][i])。
为什么呢?
Floyd要枚举中间节点,所以k不可能在i到j的最短路上,所以以上算法可以求得最小环
AC CODE
program
hy_1027;
const
eps=1e-
7
;
var
g,gg,dist:
array
[
1..500
,
1..500
]
of
longint
;
pp:
array
[
1..500
,
1..500
]
of
boolean
;
dx,dy,x,y:
array
[
1..500
]
of
double
;
p:
array
[
1..500
]
of
boolean
;
a:
array
[
1..500
]
of
longint
;
tot,i,j,k,ans,n,m:
longint
;
flag:
boolean
;
//============================================================================
function
min(a,b:
longint
):
longint
;
begin
if
a<b
then
min:=a
else
min:=b;
end
;
//============================================================================
function
right(g,h,k:
longint
):
boolean
; //判点是否在线的右边,用向量叉积的正负,同时要注
var
s:
double
; 意是否在线上。
begin
s:=(dx[h]-dx[g])*(y[k]-dy[g])-(x[k]-dx[g])*(dy[h]-dy[g]);
if
s<-eps
then
right:=
true
else
if
(
abs
(s)<eps)
and
(
abs
(
abs
(dx[h]-x[k])+
abs
(x[k]-dx[g])-
abs
(dx[g]-dx[h]))<eps)
then
right:=
true
else
right:=
false
;
end
;
//============================================================================
begin
readln(m,n);
for
i:=
1
to
m
do
readln(dx[i],dy[i]);
for
i:=
1
to
n
do
readln(x[i],y[i]);
fillchar(p,sizeof(p),
0
);
for
i:=
1
to
m
do
for
j:=
1
to
m
do
gg[i,j]:=
100000
;
for
i:=
1
to
m
do
for
j:=
1
to
m
do
begin
flag:=
true
;
for
k:=
1
to
n
do
if
((i<>j)
and
not
(right(i,j,k)))
or
((i=j)
and
((dx[i]<>x[k])
or
(dy[i]<>y[k])))
then //要判断只用一个提供的合金就可以的满足条件的情况。
begin
flag:=
false
;
break;
end
;
if
flag
then
begin
gg[i,j]:=
1
;p[i]:=
true
; p[j]:=
true
;
pp[i,j]:=
true
; //删掉没用的点。
end
;
end
;
tot:=
0
;
for
i:=
1
to
m
do
if
p[i]
then
begin
inc(tot);
a[i]:=tot;
end
;
for
i:=
1
to
tot
do
for
j:=
1
to
tot
do
g[i,j]:=
100000
;
for
i:=
1
to
m
do
for
j:=
1
to
m
do
if
pp[i,j]
then
g[a[i],a[j]]:=gg[i,j];
ans:=
100000
;
for
k:=
1
to
tot
do //Floyd
for
i:=
1
to
tot
do
for
j:=
1
to
tot
do
g[i,j]:=min(g[i,j],g[i,k]+g[k,j]);
for
i:=
1
to
tot
do //找最小环
for
j:=
1
to
tot
do
if
(i<>j)
and
(g[i,j]+g[j,i]<ans)
then
ans:=g[i,j]+g[j,i]
else
if
(i=j)
and
(g[i,j]<ans)
then
ans:=g[i,j];
if
ans=
100000
then
writeln
(
'-1'
)
else
writeln
(ans);
end
.
0 0
- [JSOI2007]合金
- bzoj 1027: [JSOI2007] 合金
- 【BZOJ 1027】 [JSOI2007]合金
- 1027: [JSOI2007]合金
- [BZOJ1027][JSOI2007]合金
- 1027: [JSOI2007]合金
- BZOJ1027: [JSOI2007]合金
- 【BZOJ 1027】[JSOI2007]合金
- BZOJ 1027 [JSOI2007]合金
- 【JSOI2007】bzoj1027 合金
- BZOJ P1027[JSOI2007]合金
- bzoj1027: [JSOI2007]合金
- BZOJ 1027 JSOI2007 合金 计算几何+Floyd
- bzoj 1027 [JSOI2007]合金 计算几何+floyd
- [BZOJ]1027: [JSOI2007]合金 计算几何+floyd
- bzoj 1027: [JSOI2007]合金(floyd最小环)
- 合金
- 合金的力量
- poj 1664 放苹果
- poj 3903 Stock Exchange
- 向量旋转
- poj 1375 Intervals
- poj 3145 Harmony Forever
- [JSOI2007]合金
- Android使用adb抓完整Log
- 与众不同易,精益求精难 — QQ导航改版设计心得
- 模块管理常规功能自定义系统的设计与实现(54--视频讲解更新高清 )
- java static变量
- Joker
- bzoj 1696 [Usaco2007 Feb]Buildin…
- poj 2828 Buy Tickets
- tyvj 1721 岛屿