LightOJ 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 |
首先根据题目意思,
一个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 }