题意 : 给出一个 N * M 的网格,然后给你 K 条鱼给你放置,现有规格为 r * r 的渔网,问你如果渔网随意放置去捕捞小鱼的情况下,捕到的最大期望值是多少?
分析 :
有一个很直观的想法就是如果将鱼放在越靠近中间的位置,其被捕捞的可能性越大
事实也的确如此,鱼的位置越靠近边缘则能覆盖到它的渔网安放位置就越少
那么这就有了一个贪心的算法
将第一条鱼放在最中间的位置算出被捕捉的概率
被捕捉的概率 = 能覆盖到当前小鱼位置的渔网个数 / 整个网格的全部安放渔网的方法数
然后从中间这个点开始向四周扩散,然后再找出概率最大的来进行扩张
因为概率越大说明其位置越靠近中间,所以首选概率最大的点进行扩张
这很像 BFS 的过程,所以我们可以使用一个优先队列来维护扩散出来的最大概率
然后选出前 K 个即可
对于每一个点能被多少个渔网放置方法覆盖,有个简便的方法
我们先分别算出横纵上的每一个点被覆盖的方法数即 (1~N, 1) 和 (1, 1~M)
然后对于中间的某个点,只要将刚刚算出来的结果进行相乘即可例如 (N, M) = (N, 1) * (1, M)
#include<bits/stdc++.h> #define LL long long using namespace std; const int maxn = 1e5 + 10; const int dr[] = {1, -1, 0, 0}; const int dc[] = {0, 0, -1, 1}; struct NODE{ double P; int row, col; NODE(){}; NODE(int r, int c, double p):row(r),col(c),P(p){}; bool operator < (const NODE &rhs) const{ return this->P < rhs.P; }; }; set<pair<int, int> > s;///由于N*M太大了,所以用set进行判重 priority_queue<NODE> que; int R[maxn], C[maxn]; int n, m, r, k; bool bound(int row, int col)///判断是否越界,越界返回 true { return (row<1 || col<1 || row>n || col>m); } int add[maxn]; inline void Calculate_R_Array(int len, int r)///计算纵轴上每个点被覆盖的方案数 { for(int i=1; i<=len-r+1; i++) add[i]++, add[i+r]--; int sum = 0; for(int i=1; i<=len; i++) sum += add[i], R[i] = sum; } inline void Calculate_C_Array(int len, int r)///计算横轴 { for(int i=1; i<=len-r+1; i++) add[i]++, add[i+r]--; int sum = 0; for(int i=1; i<=len; i++) sum += add[i], C[i] = sum; } int main(void) { while(~scanf("%d %d %d %d", &n, &m, &r, &k)){ s.clear(); while(!que.empty()) que.pop(); LL tot = (LL)(n-r+1)*(LL)(m-r+1);///注意使用 long long 存储 memset(add, 0, sizeof(add)); Calculate_R_Array(n, r); memset(add, 0, sizeof(add)); Calculate_C_Array(m, r); s.insert(make_pair(n/2+1, m/2+1)); que.push(NODE(n/2+1, m/2+1, (double)(C[m/2+1]*R[n/2+1])/(double)tot)); double ans = 0; while(k--){ NODE T = que.top(); que.pop(); ans += T.P; for(int i=0; i<4; i++){///向四个点扩散 int newr = T.row + dr[i]; int newc = T.col + dc[i]; if(bound(newr, newc)) continue; if(!s.count(make_pair(newr, newc))){ s.insert(make_pair(newr, newc)); que.push(NODE(newr, newc, (double)(C[newc]*R[newr])/(double)tot)); } } } printf("%.9f ", ans); } return 0; }