LightOJ 1313 - Protect the Mines(凸包)

1313 - Protect the Mines
Time Limit: 2 second(s) Memory Limit: 32 MB

You are a rich man, and recently you bought a place which contains some mines of rare metals like gold, platinum etc. As the metals are rare, their cost is also so high. So, you need to protect them from thieves. But things are not as easy as it looks.

So, you called a bunch of engineers to make some wired fences around the mines. As they were just engineers (not problem solvers!), they drilled some holes in random places. The idea was to put some pillars on the drilled holes and after that some wires should be set in the pillars, and finally electrifying the wires would be the completion. And of course, each mine should be surrounded by a fence. Wires should be placed between two pillars, in straight lines. The engineers drilled the holes in positions such that some of the mines might not be covered by any fences.

However, your plan is that, you can put some guards in mines that are not surrounded by any fence. To guard a single mine, it would cost G dollars, and a pillar cost is P dollars. As you are a rich man, the costs of wires are too small that they can be ignored. So, you want to put guards in some mines and surround some other mines by fences, but you want to find the optimal cost to protect all the mines. The fences may or may not be convex.

In bird's eye view, we can get the following figure (fig 1) for sample 1. There are seven pre-drilled holes (marked as circles), and six mine positions (marked as squares). The straight lines show the wires and the closed regions form the fences. The figure shows one of the optimal solutions.

 

Fig 1

So, you have to find the minimum cost for executing your plan.

Input

Input starts with an integer T (≤ 100), denoting the number of test cases.

Each case starts with a line containing four integers N (3 ≤ N ≤ 100)M (1 ≤ M ≤ 100)G (1000 ≤ G ≤ 2000) and P (100 ≤ P ≤ 200)N denotes the number of pre-drilled holes, and M denotes the number of mines. This line is followed by N lines that describe the positions of the holes, and then by M lines that describe the positions of the mines. All positions are given as pairs of integers x y on one line (0 ≤ x, y ≤ 1000). You can assume that no two positions (of holes and mines) coincide and that no three positions are collinear.

Output

For each case, print the case number and the minimum cost to protect all the mines.

Sample Input

Output for Sample Input

2

7 6 1000 100

0 0

20 0

1 10

39 10

1 20

39 20

20 30

3 9

37 9

3 21

37 21

18 24

50 24

4 3 1500 100

0 0

0 10

10 0

10 10

5 4

4 1

8 6

Case 1: 1600

Case 2: 300

 


PROBLEM SETTER: JANE ALAM JAN

 

 

首先根据题目意思,

一个mine如果可以被holes覆盖的话,肯定在一个三角形里面,因为G比P至少大10倍,所以最佳策略就是把可以覆盖的全部覆盖掉,其余的加士兵上去。

 

首先求一下凸包,把凸包内部的所有mines都找出来。

然后搞floyed, 就是看最少几步可以形成环,把所有都包括进来,

debug了好久,太坑了,以后写几何要慎重了。

  1 /* ***********************************************
  2 Author        :kuangbin
  3 Created Time  :2014/4/22 19:32:10
  4 File Name     :E:\2014ACM\专题学习\计算几何\凸包\LightOJ1313.cpp
  5 ************************************************ */
  6 
  7 #include <stdio.h>
  8 #include <string.h>
  9 #include <iostream>
 10 #include <algorithm>
 11 #include <vector>
 12 #include <queue>
 13 #include <set>
 14 #include <map>
 15 #include <string>
 16 #include <math.h>
 17 #include <stdlib.h>
 18 #include <time.h>
 19 using namespace std;
 20 
 21 // 计算几何int 版,注意如果超int,相应的要改为long long
 22 const int maxp = 1010;
 23 struct Point
 24 {
 25     int x,y;
 26     Point(){}
 27     Point(int _x,int _y)
 28     {
 29         x = _x; y = _y;
 30     }
 31     void input()
 32     {
 33         scanf("%d%d",&x,&y);
 34     }
 35     bool operator == (Point b)const
 36     {
 37         return x == b.x && y == b.y;
 38     }
 39     bool operator < (Point b)const
 40     {
 41         return x == b.x ? y < b.y : x < b.x;
 42     }
 43     Point operator - (const Point &b)const
 44     {
 45         return Point(x-b.x,y-b.y);
 46     }
 47     int operator ^ (const Point &b)const
 48     {
 49         return x*b.y - y*b.x;
 50     }
 51     int operator *(const Point &b)const
 52     {
 53         return x*b.x + y*b.y;
 54     }
 55     double len2()
 56     {
 57         return x*x + y*y;
 58     }
 59 };
 60 struct Line
 61 {
 62     Point s,e;
 63     Line(){}
 64     Line(Point _s,Point _e)
 65     {
 66         s = _s;
 67         e = _e;
 68     }
 69     //点和直线关系
 70     //1 在左侧
 71     //2 在右侧
 72     //3 在直线上
 73     int relation(Point p)
 74     {
 75         int c = (p-s)^(e-s);
 76         if(c < 0)return 1;
 77         else if(c > 0)return 2;
 78         else return 3;
 79     }
 80     bool pointonseg(Point p)
 81     {
 82         return ((p-s)^(e-s)) == 0 && ((p-s)*(p-e)) <= 0;
 83     }
 84 };
 85 struct polygon
 86 {
 87     int n;
 88     Point p[maxp];
 89     void input(int _n)
 90     {
 91         n = _n;
 92         for(int i = 0;i < n;i++)
 93             p[i].input();
 94     }
 95     struct cmp
 96     {
 97         Point p;
 98         cmp(const Point &p0){p = p0;}
 99         bool operator()(const Point &aa,const Point &bb)
100         {
101             Point a = aa, b = bb;
102             int d = (a-p)^(b-p);
103             if(d == 0)
104                 return (a-p).len2() < (b-p).len2();
105             return d > 0;
106         }
107     };
108     void norm()
109     {
110         Point mi = p[0];
111         for(int i = 1;i < n;i++)
112             mi = min(mi,p[i]);
113         sort(p,p+n,cmp(mi));
114     }
115     void getconvex(polygon &convex)
116     {
117         sort(p,p+n);
118         convex.n = n;
119         for(int i = 0;i < min(n,2);i++)
120         {
121             convex.p[i] = p[i];
122         }
123         if(n <= 2)return;
124         int &top = convex.n;
125         top = 1;
126         for(int i = 2;i < n;i++)
127         {
128             while(top && ((convex.p[top]-p[i])^(convex.p[top-1]-p[i]))<=0)
129                 top--;
130             convex.p[++top] = p[i];
131         }
132         int temp = top;
133         convex.p[++top] = p[n-2];
134         for(int i = n-3;i >= 0;i--)
135         {
136             while(top != temp && ((convex.p[top]-p[i])^(convex.p[top-1]-p[i]))<=0)
137                 top--;
138             convex.p[++top] = p[i];
139         }
140         convex.norm();
141     }
142     //判断点和任意多边形的关系
143     //3 点上
144     //2 边上
145     //1 内部
146     //0 外部
147     int relation(Point q)
148     {
149         for(int i = 0;i < n;i++)
150         {
151             if(p[i] == q)return 3;
152         }
153         for(int i = 0;i < n;i++)
154         {
155             if(Line(p[i],p[(i+1)%n]).pointonseg(q))return 2;
156         }
157         int cnt = 0;
158         for(int i = 0;i < n;i++)
159         {
160             int j = (i+1)%n;
161             int k = ((q-p[j])^(p[i]-p[j]));
162             int u = (p[i].y-q.y);
163             int v = (p[j].y-q.y);
164             if(k > 0 && u < 0 && v >= 0)cnt++;
165             if(k < 0 && v < 0 && u >= 0)cnt--;
166         }
167         return cnt != 0;
168     }
169 };
170 Point mines[maxp];
171 Point mines2[maxp];
172 int cnt;
173 polygon A,B;
174 bool check(Line v)
175 {
176     for(int i = 0;i < cnt;i++)
177         if(v.relation(mines2[i]) != 1)
178             return false;
179     return true;
180 }
181 int a[110][110];
182 int b[110][110];
183 int c[110][110];
184 int solve(polygon A)
185 {
186     int n = A.n;
187     memset(a,0,sizeof(a));
188     for(int i = 0;i < n;i++)
189         for(int j = 0;j < n;j++)
190             if(i != j && check(Line(A.p[i],A.p[j])))
191                 a[i][j] = 1;
192     for(int i = 0;i < n;i++)
193         for(int j = 0;j < n;j++)
194             b[i][j] = a[i][j];
195     for(int s = 2;s <= n;s++)
196     {
197         for(int i = 0;i < n;i++)
198             for(int j = 0;j < n;j++)
199                 c[i][j] = b[i][j];
200         memset(b,0,sizeof(b));
201         for(int i = 0;i < n;i++)
202             for(int j = 0;j < n;j++)
203                 for(int k = 0; k < n;k++)
204                     if(c[i][k] && a[k][j])
205                         b[i][j] = 1;
206         for(int i = 0;i < n;i++)
207             if(b[i][i])
208                 return s;
209     }
210     return -1;
211 }
212 
213 int main()
214 {
215     //freopen("in.txt","r",stdin);
216     //freopen("out.txt","w",stdout);
217     int T;
218     int n,m,g,p;
219     int iCase = 0;
220     scanf("%d",&T);
221     while(T--)
222     {
223         iCase++;
224         scanf("%d%d%d%d",&n,&m,&g,&p);
225         A.input(n);
226         for(int i = 0;i < m;i++)
227             mines[i].input();
228         A.getconvex(B);
229         cnt = 0;
230         //找出在凸包内的
231         for(int i = 0;i < m;i++)
232             if(B.relation(mines[i]) == 1)
233                 mines2[cnt++] = mines[i];
234         int ans1 = (m-cnt)*g;
235         int tmp = 0;
236         if(cnt)tmp = solve(A);
237         printf("Case %d: %d\n",iCase,ans1 + tmp*p);
238     }
239     return 0;
240 }

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(in)