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
10 10
0.1 0.2 0.7
0.2 0.3 0.5
0.3 0.4 0.3
0.4 0.5 0.1
0.5 0.1 0.4
0.6 0.2 0.2
0.7 0.3 0
0.8 0.1 0.1
0.9 0.1 0
1 0 0
0.1 0.2 0.7
0.2 0.3 0.5
0.3 0.4 0.3
0.4 0.5 0.1
0.5 0.1 0.4
0.6 0.2 0.2
0.7 0.3 0
0.8 0.1 0.1
0.9 0.1 0
1 0 0
0.1 0.2 0.7
0.2 0.3 0.5
0.3 0.4 0.3
0.4 0.5 0.1
0.5 0.1 0.4
0.6 0.2 0.2
0.7 0.3 0
0.8 0.1 0.1
0.9 0.1 0
1 0 0
0.1 0.2 0.7
0.2 0.3 0.5
0.3 0.4 0.3
0.4 0.5 0.1
0.5 0.1 0.4
0.6 0.2 0.2
0.7 0.3 0
0.8 0.1 0.1
0.9 0.1 0
1 0 0
Sample Output
5
HINT
Source
计算几何+floyd求最小环
首先由于保证a+b+c=1第三维可以无视
剩下的抽象成二维坐标
然后考虑两个点能合成出来的点是在它们的连线段上
问题转化为求一个点数最少的多边形包围n个点
枚举向量a[j]-a[i],判断其他点是否在它的同一边(自己确定左右,都无所谓)
然后求最小环即可
特判掉n个点共点,以及某个点n在某个向量所在的直线上但不在线段上
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 501;
const double eps = 1e-9;
const int INF = 1e9 + 7;
struct Point
{
double x, y;
Point operator - ( const Point &b ) const { Point c; c.x = x - b.x; c.y = y - b.y; return c; }
double operator * ( const Point &b ) const { return x * b.y - y * b.x; }
}a[MAXN], b[MAXN];
int ans, dis[MAXN][MAXN], m, n;
double yjq;
inline bool single_point()
{
for( int i = 1 ; i <= m ; i++ )
{
bool flag = true;
for( int j = 1 ; j <= n ; j++ )
if( abs( a[ i ].x - b[ j ].x ) > eps || abs( a[ i ].y - b[ j ].y ) > eps ) { flag = false; break; }
if( flag ) return printf( "1\n" ), true;
}
return false;
}
inline bool chk(Point x, Point y, Point z)
{
return ( x.x < z.x && y.x < z.x ) || ( x.y < z.y && y.y < z.y ) ||
( x.x > z.x && y.x > z.x ) || ( x.y > z.y && y.y > z.y );
}
int main()
{
scanf( "%d%d", &m, &n );
for( int i = 1 ; i <= m ; i++ ) scanf( "%lf%lf%lf", &a[ i ].x, &a[ i ].y, &yjq );
for( int i = 1 ; i <= n ; i++ ) scanf( "%lf%lf%lf", &b[ i ].x, &b[ i ].y, &yjq );
if( single_point() ) return 0;
for( int i = 1 ; i <= m ; i++ )
for( int j = 1 ; j <= m ; j++ )
{
dis[ i ][ j ] = INF;
if( abs( a[ i ].x - a[ j ].x ) < eps && abs( a[ i ].y - a[ j ].y ) ) continue;
bool flag = true;
for( int k = 1 ; k <= n ; k++ )
if( ( a[ i ] - a[ j ] ) * ( a[ i ] - b[ k ] ) < -eps ) { flag = false; break; }
if( flag )
{
for( int k = 1 ; k <= n ; k++ )
{
double tmp = ( a[ i ] - a[ j ] ) * ( a[ i ] - b[ k ] );
if( fabs( tmp ) < eps && chk( a[ i ], a[ j ], b[ k ] ) ) { flag = false; break; }
}
}
if( flag ) dis[ i ][ j ] = 1;
}
ans = INF;
for( int k = 1 ; k <= m ; k++ )
for( int i = 1 ; i <= m ; i++ )
for( int j = 1 ; j <= m ; j++ )
dis[ i ][ j ] = min( dis[ i ][ j ], dis[ i ][ k ] + dis[ k ][ j ] );
for( int i = 1 ; i <= m ; i++ ) ans = min( ans, dis[ i ][ i ] );
if( ans > m ) ans = -1;
return printf( "%d\n", ans ), 0;
}