洛谷 P2038 无线网络发射器选址

来源:互联网 发布:一般淘宝哪些假货多 编辑:程序博客网 时间:2024/05/18 00:54

题目描述
随着智能手机的日益普及,人们对无线网的需求日益增大。某城市决定对城市内的公共场所覆盖无线网。
假设该城市的布局为由严格平行的129 条东西向街道和129 条南北向街道所形成的网格状,并且相邻的平行街道之间的距离都是恒定值 1 。东西向街道从北到南依次编号为0,1,2…128 , 南北向街道从西到东依次编号为0,1,2…128 。
东西向街道和南北向街道相交形成路口,规定编号为x 的南北向街道和编号为y 的东西向街道形成的路口的坐标是(x , y )。 在 某 些 路口存在一定数量的公共场所 。
由于政府财政问题,只能安装一个大型无线网络发射器。该无线网络发射器的传播范围
一个以该点为中心,边长为2*d 的正方形。传播范围包括正方形边界。
例如下图是一个d = 1 的无线网络发射器的覆盖范围示意图。


现在政府有关部门准备安装一个传播参数为d 的无线网络发射器,希望你帮助他们在城市内找出合适的安装地点,使得覆盖的公共场所最多。
输入输出格式
输入格式:
输入文件名为wireless.in。
第一行包含一个整数d ,表示无线网络发射器的传播距离。
第二行包含一个整数n ,表示有公共场所的路口数目。
接下来n 行,每行给出三个整数x , y , k , 中间用一个空格隔开,分别代表路口的坐标( x , y )
以及该路口公共场所的数量。同一坐标只会给出一次。
输出格式:
输出文件名为wireless.out 。
输出一行,包含两个整数,用一个空格隔开,分别表示能覆盖最多公共场所的安装地点 方案数,以及能覆盖的最多公共场所的数量。
输入输出样例
输入样例#1:
1  
2  
4 4 10  
6 6 20  
 输出样例#1:
1 30
说明
对于100%的数据,1≤d≤20,1≤n≤20, 0≤x≤128,0≤y≤128,0<k≤1,000,000。
题解:两个方法:前缀和、差分,对于每个点(128*128个点)考虑在每个点安装能够覆盖的最大范围,如果暴力枚举显然会超时,所以用一个前缀和优化。分析一个规律,当几个点能够被同时覆盖时,那么以其中任意一个点为安装点其余的点均可以被覆盖,那么只需要找被最多覆盖的点即可,由于点具有连续性,所以可以用差分的方法来做。

总结:对于覆盖问题既可以从正面分析,去覆盖,也可以反面分析,被覆盖。两种不同的分析可以用不同的方法来做。对于差分,一定要有广义的认识,只要具有连续性,就可以考虑差分,但要注意的是差分合并时的顺序!!!
/*//前缀和思想 #include <iostream>#include <cstring>#include <algorithm>#include <cstdio>using namespace std;int D,n;int dp[300][300],a[300][300];int main(){int x,y,k;scanf("%d%d",&D,&n);while(n--){scanf("%d%d%d",&x,&y,&k);a[x+1][y+1]=k;}    for(int i=1;i<=129;i++)        for(int j=1;j<=129;j++)            dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+a[i][j];int xx=0,ans=-10000,num=0;for(int i=1;i<=129;i++){for(int j=1;j<=129;j++){    xx=dp[min(i+D,129)][min(j+D,129)]-dp[max(i-D-1,0)][min(j+D,129)]-dp[min(i+D,129)][max(j-D-1,0)]+dp[max(i-D-1,0)][max(j-D-1,0)];if(xx==ans) num++;else if(xx > ans) ans=xx,num=1;}}printf("%d %d\n",num,ans);return 0;}#include<iostream>using namespace std;long long d,ii,jj,n,x,y,k,a[1001][1001],s[1001][1001],b[100001]={0},ans,sum,t;int main(){int cm=0;    cin>>d>>n;    for(int i=1;i<=n;i++)    {        cin>>x>>y>>k;        a[x+100][y+100]=k;    }    for(int i=100;i<=250;i++)        for(int j=100;j<=250;j++)            s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];    for(int i=100;i<=228;i++)        for(int j=100;j<=228;j++)        {            cm=s[i+d][j+d]-s[i-d-1][j+d]-s[i+d][j-d-1]+s[i-d-1][j-d-1];            if(cm==ans) sum++;            else if(cm>ans) ans=cm,sum=1;        }    cout<<sum<<" "<<ans;    return 0;}putin1110 0 1064 64 100 124 54 128 53 128 10 128 4128 128 10127 0 10128 64 1064 128 930 20 10putout38 10*/ //差分的思想 /*#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>using namespace std;int n,D,dp[300][300];int main(){int x,y,k,lx,rx,ly,ry;scanf("%d%d",&D,&n);while(n--){scanf("%d%d%d",&x,&y,&k);x++;y++;lx=max(x-D,0);rx=x+D;ly=max(y-D,0);ry=y+D;for(int i=lx;i<=rx;i++) dp[i][ly]+=k,dp[i][ry+1]-=k;}int ans=-10000,sum=0;for(int i=1;i<=129;i++){for(int j=1;j<=129;j++){dp[i][j]+=dp[i][j-1];if(dp[i][j] > ans) ans=dp[i][j],sum=1;else if(dp[i][j]==ans) sum++;}}printf("%d %d\n",sum,ans);return 0;}*/