题目传送门
题目大意:
看题面吧。
思考过程:
首先很显然地一点,第三维是可以忽略的,因为c=1-a-b。
我们从最简单的情况开始考虑,如果只有两种备选合金,能配出的合金就在这两种合金连线的线段上,三种就在三种合金形成的三角形中,以此类推,n种就在这n种合金围成的凸包上。
具体做法:
floyd求最小环,具体的是如果一个点在线段ij的一边,dis[i][j]=1,否则为inf,然后跑floyd就可以了。(注意几种需要特判的情况)
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1100,inf=1000000;
const double eps=1e-6;
struct point
{
double x,y;
point operator-(point &s)
{
return (point){x-s.x,y-s.y};
}
}a[maxn],b[maxn];
int dis[maxn][maxn];
int n,m;
double operator*(point a,point b)
{
return a.x*b.y-b.x*a.y;
}
bool spj()
{
for(int i=1;i<=n;i++) if(fabs(a[i].x-a[1].x)>eps||fabs(a[i].y-a[1].y)>eps) return 0;
for(int i=1;i<=m;i++) if(fabs(b[i].x-a[1].x)>eps||fabs(b[i].y-a[1].y)>eps) return 0;
printf("1\n");
return 1;
}
bool can(point p1,point p2)
{
if(p1.x>p2.x) swap(p1,p2);
for(int i=1;i<=m;i++) if(b[i].x<p1.x||b[i].x>p2.x) return 0;
if(p1.y>p2.y) swap(p1,p2);
for(int i=1;i<=m;i++) if(b[i].y<p1.y||b[i].y>p2.y) return 0;
return 1;
}
int judge(point p1,point p2)
{
int c1=0,c2=0;
for(int i=1;i<=m;i++)
{
double t=(p2-p1)*(b[i]-p1);
if(t>eps) c1++;
if(t<-eps) c2++;
if(c1*c2) return 0;
}
if(!c1&&!c2&&can(p1,p2)) return -1;
if(c1) return 1;
if(c2) return 2;
return 3;
}
void floyd()
{
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
int ans=inf;
for(int i=1;i<=n;i++) ans=min(ans,dis[i][i]);
if(ans==inf||ans<=2) printf("-1\n");
else printf("%d\n",ans);
}
void work()
{
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
int flag=judge(a[i],a[j]);
if(flag==-1) { printf("2\n");return; }
else if(flag==0) dis[i][j]=inf;
else if(flag==1) dis[i][j]=1;
else if(flag==2) dis[j][i]=1;
else { dis[i][j]=1;dis[j][i]=1; }
}
}
floyd();
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dis[i][j]=inf;
double ttt;
for(int i=1;i<=n;i++) scanf("%lf%lf%lf",&a[i].x,&a[i].y,&ttt);
for(int i=1;i<=m;i++) scanf("%lf%lf%lf",&b[i].x,&b[i].y,&ttt);
if(spj()) return 0;
work();
return 0;
}