[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 };

 

posted @ 2018-05-21 09:56  skylee03  阅读(170)  评论(0编辑  收藏  举报