BZOJ 1027 合金
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
HINT
Source
首先可以知道第三个比例是吃翔的(明显啊,1-前面两个就是第三个)。其次,我们再说一个结论:将合金的第一个比例看做x,第二个看做y,则n种合金所能形成的所有合金就是在这n种合金的凸包中(凸包的经典应用)。
因此,问题转换为对目标点求凸包,在从给定点中找出一个闭包将目标凸包包裹起来。问题再一次转换,对于所有合法的边,我们要求的就是一个边权最小的环,就是求floyed求最小环。
好,那么问题就来了。怎么连边呢,首先边不能穿过凸包,还有所有边的方向要跟凸包边的方向一致。(呵呵,慢慢写吧,我是不会告诉你有数据有鬼畜点的,WA了自己拍吧)。然后还有一点,有些特判不能省,详情见我code的spj。
1 #include<ctime> 2 #include<iostream> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstdio> 7 #include<cstdlib> 8 using namespace std; 9 10 #define rhl 100 11 #define inf (1<<29) 12 #define esp (1e-10) 13 #define maxn 510 14 int ans = inf,m,n,tot,dis[maxn][maxn]; 15 bool in[maxn]; 16 17 inline double equal(double a,double b) { return fabs(a-b) < esp; } 18 19 inline bool dd(double a,double b) { if (equal(a,b)) return true; return a >= b; } 20 inline bool dy(double a,double b) { if (equal(a,b)) return false; return a > b; } 21 22 inline bool xd(double a,double b) { if (equal(a,b)) return true; return a <= b; } 23 24 struct NODE 25 { 26 double x,y; 27 friend inline bool operator == (NODE a,NODE b) { return equal(a.x,b.x)&&equal(a.y,b.y); } 28 friend inline bool operator < (NODE a,NODE b) { if (a.x == b.x) return a.y < b.y; return a.x < b.x; } 29 friend inline NODE operator - (NODE a,NODE b) { return (NODE) {a.x - b.x,a.y - b.y}; } 30 friend inline double operator / (NODE a,NODE b) { return a.x*b.y-a.y*b.x; } 31 inline NODE ra() 32 { 33 int xx,yy; 34 do xx = rand()%rhl,yy = rand()%rhl; 35 while (equal(1.0*xx,x)||equal(1.0*yy,y)); 36 return (NODE) {1.0*xx,1.0*yy}; 37 } 38 inline void read() { scanf("%lf %lf",&x,&y); } 39 }pri[maxn],aim[maxn],ch[maxn]; 40 struct LINE 41 { 42 double a,b,c; 43 inline bool on(NODE p) { return equal(0,a*p.x+b*p.y+c); } 44 }; 45 struct SEG 46 { 47 NODE a,b; 48 inline LINE extend() { return (LINE) {a.y-b.y,b.x-a.x,b.y*(a.x-b.x)-b.x*(a.y-b.y)}; } 49 inline bool on(NODE p) 50 { 51 if (p == a) return true; 52 if (p == b) return true; 53 return (dd(p.x,min(a.x,b.x))&xd(p.x,max(a.x,b.x)))&&(dd(p.y,min(a.y,b.y))&xd(p.y,max(a.y,b.y))); 54 } 55 }; 56 57 inline bool para(LINE l1,LINE l2) { return equal(l1.a * l2.b,l1.b * l2.a); } 58 59 inline NODE cp(LINE l1,LINE l2) 60 { 61 double a1 = l1.a,b1 = l1.b,c1 = l1.c; 62 double a2 = l2.a,b2 = l2.b,c2 = l2.c; 63 double ry = (c2*a1-c1*a2)/(b1*a2-b2*a1),rx = (c1*b2-c2*b1)/(b1*a2-b2*a1); 64 return (NODE) {rx,ry}; 65 } 66 67 inline void convex() 68 { 69 sort(aim+1,aim+n+1); 70 n = unique(aim+1,aim+n+1) - aim - 1; 71 for (int i = 1;i <= n;++i) 72 { 73 while (tot > 1 &&(ch[tot] - ch[tot - 1])/(aim[i] - ch[tot-1]) <= 0) --tot; 74 ch[++tot] = aim[i]; 75 } 76 int k = tot; 77 for (int i = n-1;i;--i) 78 { 79 while (tot > k &&(ch[tot] - ch[tot - 1])/(aim[i] - ch[tot-1]) <= 0) --tot; 80 ch[++tot] = aim[i]; 81 } 82 if (n > 1) --tot; 83 ch[0] = ch[tot]; 84 } 85 86 inline int find(NODE p) 87 { 88 NODE q = p.ra(); SEG s = (SEG) {p,q},t; LINE l = s.extend(),l1; int cnt; 89 cnt = 0; 90 for (int i = 1;i <= tot;++i) 91 { 92 t = (SEG) {ch[i],ch[i-1]}; 93 if ((t.extend()).on(p)&&t.on(p)) return false; 94 l1 = t.extend(); 95 if (para(l,l1)) continue; 96 q = cp(l,l1); 97 if (dd(q.x,p.x)&&t.on(q)) ++cnt; 98 } 99 if (cnt & 1) return true; 100 return false; 101 } 102 103 inline bool cross(NODE p,NODE q) 104 { 105 for (int i = 1;i <= tot;++i) 106 if (dy((q - p) / (ch[i] - p),0)) return false; 107 return true; 108 } 109 110 inline void ready() 111 { 112 sort(pri+1,pri+m+1); 113 m = unique(pri+1,pri+m+1) - pri - 1; 114 for (int i = 1;i <= m;++i) in[i] = find(pri[i]); 115 memset(dis,0x7,sizeof(dis)); 116 for (int i = 1;i <= m;++i) if (!in[i]) 117 for (int j = 1;j <= m;++j) 118 if (i != j && !in[j] &&dis[j][i] > maxn) 119 if (cross(pri[i],pri[j])) 120 dis[i][j] = 1; 121 } 122 123 inline void floyd() 124 { 125 for (int k = 1;k <= m;++k) 126 for (int i = 1;i <= m;++i) 127 if (dis[i][k] < maxn) 128 for (int j = 1;j <= m;++j) 129 dis[i][j] = min(dis[i][j],dis[i][k]+dis[k][j]); 130 for (int i = 1;i <= m;++i) ans = min(dis[i][i],ans); 131 if (ans > maxn) ans = -1; 132 for (int i = 1;i <= m;++i) 133 for (int j = i+1;j <= m;++j) 134 { 135 SEG s = (SEG) {pri[i],pri[j]}; int k; 136 for (k = 1;k <= n;++k) 137 if (!(equal((aim[k]-pri[i])/(aim[k]-pri[j]),0)&&s.on(aim[k]))) break; 138 if (k == n + 1) { ans = 2; break; } 139 } 140 printf("%d",ans); 141 } 142 143 inline void spj() { if (n == 1) for (int i = 1;i <= m;++i) if (pri[i] == aim[1]) puts("1"),exit(0); } 144 145 int main() 146 { 147 freopen("1027.in","r",stdin); 148 freopen("1027.out","w",stdout); 149 srand(233); 150 scanf("%d %d",&m,&n); double w; 151 for (int i = 1;i <= m;++i) 152 pri[i].read(),scanf("%lf",&w); 153 for (int i = 1;i <= n;++i) 154 aim[i].read(),scanf("%lf",&w); 155 convex(); 156 spj(); 157 ready(); 158 floyd(); 159 fclose(stdin); fclose(stdout); 160 return 0; 161 }
高考结束,重新回归。