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

时间:2023-03-10 04:19:55
【BZOJ 1027】 (凸包+floyd求最小环)

【题意】

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

【分析】

  只要考虑前两个物质的比例,因为加起来等于1。

  如果你看过zoj3154,就会知道这题的模型,用二元组表示合金(x1,y1)(x2,y2),他们能混合成的合金就是线段(x1,y1)->(x2,y2),

  那么一堆点组成的合金就是那些点组成的凸包面积。

  然后看了po姐的下一步转化,就是若点i->j的一侧包含了所有B点集,那么i->j连一条边,然后floyd求最小环即可。

  有一个地方我一开始错了:若B中有一个点在i->j上,要判断是不是线段上的,若只是直线上,也是不能组成的。

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define Maxn 510
#define INF 0x7fffffff int m,n; int mymin(int x,int y) {return x<y?x:y;} const double eps=0.0001; struct node
{
double x,y;
};
node t[Maxn*]; node operator - (node x,node y)
{
node P;
P.x=x.x-y.x;P.y=x.y-y.y;
return P;
// return node{x.x-y.x,x.y-y.y};
} double myabs(double x) {return x>?x:-x;} bool operator != (node x,node y) {return myabs(x.x-y.x)>eps||myabs(x.y-y.y)>eps;} double Cross(node x,node y)
{
return x.x*y.y-x.y*y.x;
} double Dot(node x,node y)
{
return x.x*y.x+x.y*y.y;
} int dis[Maxn][Maxn]; void floyd()
{
for(int k=;k<=m;k++)
for(int i=;i<=m;i++)
for(int j=;j<=m;j++)
dis[i][j]=mymin(dis[i][j],dis[i][k]+dis[k][j]);
} int main()
{
scanf("%d%d",&m,&n);
for(int i=;i<=m+n;i++)
{
double c;
scanf("%lf%lf%lf",&t[i].x,&t[i].y,&c);
}
memset(dis,,sizeof(dis));
for(int i=;i<=m;i++)
for(int j=;j<=m;j++) //if(i!=j&&t[i]!=t[j])
{
bool ok=;
for(int k=m+;k<=n+m;k++)
{
if(Cross(t[j]-t[i],t[k]-t[i])>eps) {ok=;break;}
if(myabs(Cross(t[j]-t[i],t[k]-t[i]))<=eps&&Dot(t[i]-t[k],t[j]-t[k])>eps) {ok=;break;}
}
if(ok) dis[i][j]=;
// if(ok) {dis[i][j]=1;printf("%d->%d\n",i,j);}
}
floyd();
int ans=INF;
for(int i=;i<=m;i++) ans=mymin(ans,dis[i][i]);
if(ans>m) ans=-;
printf("%d\n",ans);
return ;
}

2017-02-20 22:09:40