P4049 [JSOI2007]合金

题意

因为\(a+b+c=1\),因此只要知道\(a,b\),就可以知道\(c\)。也就是说只用\(a,b\)即可表示出一种材料/合金,我们将每种材料/合金表示为坐标系上的

一种材料\(a\)能表示出的合金为\(a\)
两种材料\(a,b\)能表示出的合金为线段\(ab\)上的所有点。
三种材料\(a,b,c\)能表示出的合金为\(ab,bc,ac\)围成的三角形中所有的点。
推广可得:\(k\)种材料能表示出的合金为这\(k\)个点的凸包内的所有点。

我们枚举每一对材料\((i,j)\),满足所有需求点都在线段\(ij\)一边,之后根据在哪边连边,之后跑最小环即可。

注意特判只有重点和共线的情况。

code:

#include<bits/stdc++.h>
using namespace std;
#define re register
const int maxn=510;
const double eps=1e-8;
const int inf=0x3f3f3f3f;
int n,m,ans=inf;
int dis[maxn][maxn];
double xmin=inf,xmax=-inf,ymin=inf,ymax=-inf;
struct Point
{
    double x,y;
    inline double len(){return sqrt(x*x+y*y);}
    Point operator+(const Point a)const{return (Point){x+a.x,y+a.y};}
    Point operator-(const Point a)const{return (Point){x-a.x,y-a.y};}
    Point operator*(const double k){return (Point){x*k,y*k};}
    Point operator/(const double k){return (Point){x/k,y/k};}
    double operator*(const Point a)const{return x*a.y-y*a.x;}
    double operator&(const Point a)const{return x*a.x+y*a.y;}
}p1[maxn],p2[maxn];
inline int dcmp(double x)
{
	if(fabs(x)<=eps)return 0;
	return x<0?-1:1;
}
inline bool check(double x1,double x2,double x3,double x4)
{
	if(dcmp(x1-x2)>0)swap(x1,x2);
	return dcmp(x1-x3)<=0&&dcmp(x4-x2)<=0;
}
inline void solve(int x,int y)
{
	int cnt1=0,cnt2=0;
	for(re int i=1;i<=m;i++)
	{
		double tmp=(p1[y]-p1[x])*(p2[i]-p1[x]);
		if(dcmp(tmp)<0)cnt1++;
		if(dcmp(tmp)>0)cnt2++;
	} 
	if(!cnt1&&!cnt2&&check(p1[x].x,p1[y].x,xmin,xmax)&&check(p1[x].y,p1[y].y,ymin,ymax)){puts("2");exit(0);}//共线。 
	if(cnt1&&cnt2)return;
	if(cnt1)dis[x][y]=1;
	if(cnt2)dis[y][x]=1;
}
int main()
{
	scanf("%d%d",&n,&m);
	double tmp;
	for(re int i=1;i<=n;i++)scanf("%lf%lf%lf",&p1[i].x,&p1[i].y,&tmp);
	for(re int i=1;i<=m;i++)
	{
		scanf("%lf%lf%lf",&p2[i].x,&p2[i].y,&tmp);
		xmin=min(xmin,p2[i].x),xmax=max(xmax,p2[i].x);
		ymin=min(ymin,p2[i].y),ymax=max(ymax,p2[i].y);
	}
	bool flag=1;
	for(re int i=1;i<=n;i++)if(dcmp(p1[i].x-p1[1].x)!=0||dcmp(p1[i].y-p1[1].y)!=0)flag=0;
	for(re int i=1;i<=n;i++)if(dcmp(p2[i].x-p2[1].x)!=0||dcmp(p2[i].y-p2[1].y)!=0)flag=0;
	if(flag){puts("1");return 0;}//重点。 
	memset(dis,0x3f,sizeof(dis));
	for(re int i=1;i<=n;i++)
		for(re int j=i+1;j<=n;j++)
			solve(i,j);
	for(re int k=1;k<=n;k++)
		for(re int i=1;i<=n;i++)
		{
			if(dis[i][k]==inf)continue;
			for(re int j=1;j<=n;j++)dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
		}
	for(re int i=1;i<=n;i++)ans=min(ans,dis[i][i]);
	if(ans==inf||ans<2)puts("-1");
	else printf("%d",ans);
	return 0;
} 
posted @ 2020-01-19 09:55  nofind  阅读(130)  评论(0编辑  收藏  举报