CF912D Fishes

题目链接:http://codeforces.com/contest/912/problem/D

题目大意:

  在一个\(n \times m\)的网格中放鱼(每个网格只能放一条鱼),用一个\(r \times r\)的网随机地捕一次鱼,问如何放置鱼能使得捕到的鱼的期望值最大,求最大值。

知识点:  优先队列、概率与期望

解题思路:

  要使捕到鱼的期望值最大,就应该往最有可能被渔网捞到的格子里放鱼。

  \(P(某个格子被捞到)= N_1(渔网能捞到这个格子的放置方案数)/N_2(渔网总放置方案数),\)

  \(N(渔网总放置方案数) = (n-r+1)\times(m-r+1)\)

  而要求\(N_1\),我们可以先算出最左边一列和最上边一行的各个格子对应的\(N_1\),\(N_1(x,y) = N_1(x,0) \times N_1(0,y)\)。于是我们可以从最中间的格子开始(直觉告诉我们:最中间的格子总是最有可能被捞到),用一个优先队列维护,每次都往上下左右四个方向拓展,找出前 \(k\) 个最有可能被捞到的位置所对应的期望值,加起来所得到的总和即为答案。

AC代码:

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 const int maxn = 1e5+5;
 5 const int cx[4]={1,-1,0,0},cy[4]={0,0,1,-1};
 6 
 7 int line[maxn],col[maxn];
 8 struct node{
 9     int x,y;
10     double z;
11     friend bool operator <(const node &a,const node &b){
12         return a.z<b.z;
13     }
14 };
15 map<pair<int,int>,int> vis;
16 priority_queue<node> q;
17 
18 int main(){
19     int n,m,r,k;
20     scanf("%d%d%d%d",&n,&m,&r,&k);
21     for(int i=1;i<=(n+1)/2;i++){
22         if(i<=n-r+1)    line[i]=min(i,r);
23         else    line[i]=line[i-1];
24     }
25     for(int i=n,j=1;i>(n+1)/2;i--,j++)
26         line[i]=line[j];
27 
28     for(int i=1;i<=(m+1)/2;i++){
29         if(i<=m-r+1)    col[i]=min(i,r);
30         else    col[i]=col[i-1];
31     }
32     for(int i=m,j=1;i>(m+1)/2;i--,j++)
33         col[i]=col[j];
34 
35     double tot=(double)(n-r+1)*(m-r+1),ans=0.0;
36     node now,next;
37     now.x=(n+1)/2,now.y=(m+1)/2;
38     now.z=(double)line[now.x]*col[now.y]/tot;
39     q.push(now);
40     vis[make_pair(now.x,now.y)]=1;
41     while(k--){
42         now=q.top();
43         q.pop();
44         ans+=now.z;
45         for(int i=0;i<4;i++){
46             int nx=now.x+cx[i],ny=now.y+cy[i];
47             if(nx>0&&nx<=n&&ny>0&&ny<=m&&!vis[make_pair(nx,ny)]){
48                 next.x=nx,next.y=ny,next.z=(double)line[next.x]*col[next.y]/tot;
49                 q.push(next);
50                 vis[make_pair(nx,ny)]=1;
51             }
52         }
53     }
54     printf("%.10lf\n",ans);
55 
56     return 0;
57 }

 

转载于:https://www.cnblogs.com/Blogggggg/p/8319001.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值