Codeforces 912D Fishs ( 贪心 && 概率期望 && 优先队列 )

题意 : 给出一个 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\n", ans);
    }
    return 0;
}
View Code

 

posted @ 2018-02-08 18:40  qwerity  阅读(191)  评论(0编辑  收藏  举报