[TC-HouseProtection]House Protection
题目大意:
一个平面直角坐标系中有给定的$n(n\le50)$个红点和$m(m\le50)$个蓝点,每个点可以选择画一个半径为$r$(所有的$r$相同)的圆或不画。圆的半径上限为$R(R\le1000)$。且不同颜色的点所画成的圆不能相交,问所有圆面积的和最大是多少?
思路:
枚举每一对不同颜色的点,求出所有可能的$r$,显然这样的$r$有$nm$个。
对于不同颜色的点,若以$r$为半径画出的圆相交,则在这两个点之间连边,题目转化为最大独立集问题。有结论:最大独立集=点数-二分图最大匹配。用Dinic求最大匹配即可。
对$r$排序,则每次只会增加新的边,只需要在原来的基础上进行增广即可。时间复杂度$O(n^4)$。
1 #include<cmath> 2 #include<queue> 3 #include<vector> 4 #include<cstring> 5 #include<climits> 6 #include<algorithm> 7 class HouseProtection { 8 private: 9 static constexpr int N=50,M=102; 10 static constexpr double pi=M_PI; 11 using Point=std::pair<int,int>; 12 struct Length { 13 double l; 14 int u,v; 15 bool operator < (const Length &rhs) const { 16 return l<rhs.l; 17 } 18 }; 19 struct Edge { 20 int from,to,remain,next; 21 }; 22 Point a[N],b[N]; 23 std::vector<Length> len; 24 std::vector<Edge> e; 25 int s,t,lev[M],cur[M],h[M]; 26 double sqr(const double &x) const { 27 return x*x; 28 } 29 double dist(const Point &a,const Point &b) const { 30 return sqrt(sqr(a.first-b.first)+sqr(a.second-b.second)); 31 } 32 void add_edge(const int &u,const int &v,const int &w) { 33 e.push_back({u,v,w,h[u]}); 34 h[u]=e.size()-1; 35 } 36 void bfs() { 37 memset(lev,-1,sizeof lev); 38 lev[s]=0; 39 std::queue<int> q; 40 q.push(s); 41 while(!q.empty()) { 42 const int &x=q.front(); 43 for(register int i=h[x];~i;i=e[i].next) { 44 const int &y=e[i].to,&r=e[i].remain; 45 if(r&&!~lev[y]) { 46 lev[y]=lev[x]+1; 47 q.push(y); 48 } 49 } 50 q.pop(); 51 } 52 } 53 int dfs(const int &x,const int &flow) { 54 if(x==t) return flow; 55 for(int &i=cur[x];~i;i=e[i].next) { 56 const int &y=e[i].to; 57 if(e[i].remain&&lev[y]>lev[x]) { 58 if(int d=dfs(y,std::min(flow,e[i].remain))) { 59 e[i].remain-=d; 60 e[i^1].remain+=d; 61 return d; 62 } 63 } 64 } 65 return 0; 66 } 67 int dinic() { 68 int maxflow=0; 69 for(;;) { 70 bfs(); 71 if(!~lev[t]) break; 72 memcpy(cur,h,sizeof h); 73 while(int flow=dfs(s,INT_MAX)) { 74 maxflow+=flow; 75 } 76 } 77 return maxflow; 78 } 79 public: 80 double safetyFactor(const std::vector<int> &possibleXForBlue,const std::vector<int> &possibleYForBlue,const std::vector<int> &possibleXForRed,const std::vector<int> &possibleYForRed,const int &R) { 81 memset(h,-1,sizeof h); 82 const int n=possibleXForBlue.size(),m=possibleXForRed.size(); 83 for(register int i=0;i<n;i++) { 84 a[i]={possibleXForBlue[i],possibleYForBlue[i]}; 85 } 86 for(register int i=0;i<m;i++) { 87 b[i]={possibleXForRed[i],possibleYForRed[i]}; 88 } 89 for(register int i=0;i<n;i++) { 90 for(register int j=0;j<m;j++) { 91 const double dis=dist(a[i],b[j])/2; 92 if(dis<R) len.push_back({dis,i,j}); 93 } 94 } 95 len.push_back({(double)R,-1,-1}); 96 std::sort(len.begin(),len.end()); 97 s=n+m,t=n+m+1; 98 for(int i=0;i<n;i++) { 99 add_edge(s,i,1); 100 add_edge(i,s,0); 101 } 102 for(int i=0;i<m;i++) { 103 add_edge(n+i,t,1); 104 add_edge(t,n+i,0); 105 } 106 int match=0; 107 double ans=0; 108 for(register auto &e:len) { 109 match+=dinic(); 110 ans=std::max(ans,pi*sqr(e.l)*(n+m-match)); 111 if(e.l<R) { 112 add_edge(e.u,n+e.v,1); 113 add_edge(n+e.v,e.u,0); 114 } 115 } 116 return ans; 117 } 118 };