题意:在一个n*m的鱼塘里面放置k条鱼,每次可以选定一个r*r的矩阵并获得矩阵内鱼的数量的分数。请问该如何在鱼塘里面放置鱼,使得最后的期望得分最大。
思路:直接通过枚举放置鱼的位置计算期望得分明显非常非常不现实,于是我们换一种计算思路我们去计算各点放置鱼之后可以得到的期望得分,然后取前k大的位置得分即可得到题目所说的答案。有一个明显的结论(r,r)这点的期望得分一定期望得分最高的点之一,于是解决方案就出来了。以(r,r)为起点向四个方向进行bfs,以map代替vis[][]标记并用priority_queue维护数据,取前k大期望得分点进行累加。
C++代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,r,k;
double ans=0;
int dx[4] = {-1,1,0,0};
int dy[4] = {0,0,-1,1};
struct node
{
int x,y;
double z;
friend bool operator<( const node&a , const node&b )
{
return a.z<b.z;
}
};
priority_queue<node>PQ;
map<pair<int,int>,int>mp;
double fun( int x , int y ) //期望得分计算函数
{
double x1 = min( 1.0*x , 1.0*n-x+1 ); x1 = min( x1 , 1.0*n-r+1 ); x1 = min( x1 , r*1.0 );
double y1 = min( 1.0*y , 1.0*m-y+1 ); y1 = min( y1 , 1.0*m-r+1 ); y1 = min( y1 , r*1.0 );
return x1*y1/(n-r+1)/(m-r+1);
}
bool ok( int x , int y )
{
return x>=1&&x<=n&&y>=1&&y<=m&&!mp.count(make_pair(x,y));
}
int main()
{
scanf ( "%d%d%d%d" , &n , &m , &r , &k );
node p;
p.x = r;
p.y = r;
p.z = fun( r , r );
mp[make_pair(r,r)] = 1;
PQ.push(p);
while( k-- )
{
p = PQ.top();
PQ.pop();
int x = p.x;
int y = p.y;
ans += p.z;
for ( int i=0 ; i<4 ; i++ )
{
int tx = x+dx[i];
int ty = y+dy[i];
if ( ok( tx , ty ) )
{
mp[make_pair(tx,ty)] = 1;
p.x = tx;
p.y = ty;
p.z = fun( p.x , p.y );
PQ.push(p);
}
}
}
printf ( "%.10lf\n" , ans );
return 0;
}