ZZULIOJ 1730通信基站全排列+DFS

xiaoxiao2021-02-27  302

题目链接:https://acm.zzuli.edu.cn/zzuliacm/problem.php?id=1730

此题的关键就在于找到基站的辐射半径

枚举在呢些点建基电站,用一个全排列,1代表建,0代表不建。我们把0的点存为y[],1的点存为x[],然后就是从x[]里面选若干个点引半径做圆 来覆盖y[]里面的所有点,只需要求出最小半径和.

#include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> #define INF 0x3f3f3f3f using namespace std; double a[10],b[10]; int vis[10],n; double Cs,Cr; int x[10],y[10]; double bj[10]; int s1,s2; double sum,minn; void dfs(int v) { if(v==s1+1)//已经把所有不建基站的地方都覆盖 { double cnt=0; for(int i=1; i<=s2; i++) cnt+=bj[i]; sum=min(sum,cnt); return; } for(int i=1; i<=s2; i++)//把s2个建基站的半径扩大来覆盖s1个不建基站的地方 { double dis=sqrt((a[x[i]]-a[y[v]])*(a[x[i]]-a[y[v]])+(b[x[i]]-b[y[v]])*(b[x[i]]-b[y[v]]));//半径 double ls=bj[i]; bj[i]=max(bj[i],dis);//注意,选最大的才能全部被覆盖 dfs(v+1); bj[i]=ls;//回溯,这个基站不向外扩展 } } void fun() { s1=0,s2=0; for(int i=1; i<=n; i++) { if(vis[i]==0) y[++s1]=i;//不建基站的放在y数组 else x[++s2]=i;//建基站的放在x数组 } if(s1!=0&&s2!=0)// s1==0即全都不建基站,不成立 / s2==0即全都建基站,在minn初始化的时候已经算过 { memset(bj,0,sizeof(bj));//存放基站的辐射半径 sum=INF; //基站的辐射半径和 dfs(1); minn=min(minn,Cs*s2+Cr*sum); } } void judge() { //用01的全排列,1表示在该地方建基站,0表示不建 for(int i=1; i<=n; i++) { for(int j=1; j<=n; j++) vis[j]=1; for(int j=1; j<=i; j++)//有i个建基站的建筑 vis[j]=0; do { fun();//枚举这i个基站分别建在呢个建筑 } while(next_permutation(vis+1,vis+n+1)); } } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%lf%lf",&n,&Cs,&Cr); for(int i=1; i<=n; i++) scanf("%lf%lf",&a[i],&b[i]); minn=Cs*n;//每座建筑都建立基站 judge(); printf("%.2f\n",minn); } return 0; }

转载请注明原文地址: https://www.6miu.com/read-1302.html

最新回复(0)