感觉网上很多题解写的似乎不清楚,这里说一下我的思路
显然对于每个用户的材料(设其比例为Ai,Bi,Ci),
我们要么最多用3种原料(设其比例为ai,bi,ci)混合成需要材料,要么一定混合不成,具体原因往下看
我们设这3种原料所取比例为x1,x2,x3,可得
x1*a1+x2*a2+x3*a3=Ai
x1*b1+x2*b2+x3*b3=Bi
x1*(1-a1-b1)+x2*(1-a2-b2)+x3*(1-a3-b3)=1-Ai-Bi
整理第三个式子可得x1+x2+x3=1 x3=1-x1-x2 (注意这里x1,x2,x3>=0)
带回到前两个式子可得
x1*a1+x2*a2+(1-x1-x2)*a3=Ai
x1*b1+x2*b2+(1-x1-x2)*b3=Bi
整理可得
x1*(a1-a3)+x2*(a2-a3)=Ai-a3
x1*(b1-b3)+x2*(b2-b3)=Bi-b3
看到这个式子大家仔细想就会发现,这其实就是:
向量(a1-a3,b1-b3)和(a2-a3,b2-b3)能否表示向量(Ai-a3,Bi-b3)
根据平面向量的理论我们知道上面的结论是正确的
学过向量的同学可能还会听过这样一个结论(很好证)
设OABC四点,B在线段AC上,O不与ABC共线
则向量OB=a向量OA+b向量OC 一定满足a+b=1 而这里我们的要求也是x1+x2<=1
也就是如果把ai,bi和A,B看做材料点(ai,bi)和原料点(Ai,Bi)
如果用户所需材料i能被原料融合,当且仅当存在三个原料点构成的三角形能把材料点围起来
于是下面的思路就很明显了,我们先求出原料点所组成的凸包,如果所有用户都在凸包内则有解否则无解
接下来我们要找的是最少凸包上的点组成的多边形就能把所有原料点包含了
首先我们要理解什么是包含,我们从凸包一点出发,沿着下凸线到上凸线的顺序走回起点
这样凸包上的每条边就是一个向量,包含的意思就是:每个原料点都必须在每个向量的左边(叉积判断)
于是这就好办了,于是我们穷举向量的起点i终点j,如果所有原料点都在这个向量的左边那么d[i,j]=1 否则d[i,j]=inf
下面我们只要求出一个最小环即可,这可以用floyd搞定
注意这里凸包上是不能存在三点共线的
比较恶心的是这道题要注意精度问题

  1 const eps=1e-10;
  2 type point=record
  3        x,y:double;
  4      end;
  5 
  6 var a,b:array[0..510] of point;
  7     w:array[0..510] of longint;
  8     f:array[0..510,0..510] of longint;
  9     ans,i,j,k,p,n,m:longint;
 10     ch:boolean;
 11 
 12 function min(a,b:longint):longint;
 13   begin
 14     if a>b then exit(b) else exit(a);
 15   end;
 16 
 17 procedure swap(var a,b:point);
 18   var c:point;
 19   begin
 20     c:=a;
 21     a:=b;
 22     b:=c;
 23   end;
 24 
 25 
 26 procedure sort(l,r:longint);
 27   var i,j:longint;
 28       p:point;
 29   begin
 30     i:=l;
 31     j:=r;
 32     p:=a[(l+r) shr 1];
 33     repeat
 34       while (a[i].x<p.x) or (a[i].x=p.x) and (a[i].y<p.y) do inc(i);
 35       while (p.x<a[j].x) or (a[j].x=p.x) and (p.y<a[j].y) do dec(j);
 36       if not(i>j) then
 37       begin
 38         swap(a[i],a[j]);
 39         inc(i);
 40         dec(j);
 41       end;
 42     until i>j;
 43     if l<j then sort(l,j);
 44     if i<r then sort(i,r);
 45   end;
 46 
 47 function cross(a,b,c:point):double;
 48   begin
 49     exit((b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y));
 50   end;
 51 
 52 function check:boolean;
 53   var i,j:longint;
 54   begin
 55     dec(k);
 56     for i:=1 to k do
 57       for j:=1 to n do
 58         if cross(a[w[i]],a[w[i+1]],b[j])<-eps then exit(false);
 59     exit(true);
 60   end;
 61 
 62 begin
 63   readln(m,n);
 64   for i:=1 to m do
 65     readln(a[i].x,a[i].x,a[i].y);
 66   for i:=1 to n do
 67     readln(b[i].x,b[i].x,b[i].y);
 68   if n=0 then
 69   begin
 70     writeln(0);
 71     halt;
 72   end;
 73   for i:=1 to m do
 74   begin
 75     ch:=true;
 76     for j:=1 to n do
 77       if (a[i].x<>b[j].x) or (a[i].y<>b[j].y) then
 78       begin
 79         ch:=false;
 80         break;
 81       end;
 82     if ch then //这里特判一下
 83     begin
 84       writeln(1);
 85       halt;
 86     end;
 87   end;
 88   sort(1,m);
 89   k:=1;
 90   w[1]:=1;
 91   for i:=2 to m do
 92   begin
 93     while (k>1) and (cross(a[w[k-1]],a[w[k]],a[i])<eps) do dec(k);
 94     inc(k); w[k]:=i;
 95   end;
 96   j:=k;
 97   for i:=m-1 downto 1 do
 98   begin
 99     while (k>j) and (cross(a[w[k-1]],a[w[k]],a[i])<eps) do dec(k);
100     inc(k); w[k]:=i;
101   end;
102   if check then
103   begin
104     for i:=1 to k do
105       for j:=1 to k do
106       begin
107         f[i,j]:=m;
108         if i<>j then
109         begin
110           ch:=true;
111           for p:=1 to n do
112             if cross(a[w[i]],a[w[j]],b[p])<-eps then
113             begin
114               ch:=false;
115               break;
116             end;
117           if ch then f[i,j]:=1;
118         end;
119       end;
120 
121     for p:=1 to k do
122       for i:=1 to k do
123         for j:=1 to k do
124           f[i,j]:=min(f[i,j],f[i,p]+f[p,j]);
125     ans:=m;
126     for i:=1 to k do
127       ans:=min(ans,f[i,i]);
128     writeln(ans);
129   end
130   else writeln(-1);
131 end.
View Code

 

posted on 2015-03-07 21:40  acphile  阅读(147)  评论(0编辑  收藏  举报