• Luogu [P1378] 油滴扩展


    首先,原题在这

    恩,让我们进入正题:油滴扩展——显然,这道题是个搜索题,并且是个打眼一看上去就比较恶心的搜索题。

    但是,这道题细节恶心,并不代表这道题思路难。

    题意大家都了解了,让我们先来把细节问题坑点解决:

    1.坐标范围为【-1000,1000】,有负数怎么办?

      解决方法很简单粗暴:将所有坐标加上1000就行了,然后就可视为所有坐标都为正数了。

    2.让输出的答案为剩余的面积,还要四舍五入。

      解决方法也很简单:先搜索求出最大覆盖面积,然后将答案 + = 0.5 ,用矩形总面积减去答案输出即可。

    然后就是代码实现部分,先声明变量:

    int n; //n个油滴 
    int X1,Y1,X2,Y2;//矩形区域 
    double ans;//覆盖的最大面积 
    
    int x[10],y[10];//编号为 [i] 的油滴的坐标 
    double r[10];   //编号为 [i] 的油滴的半径 
    
    bool b[10]; //记录此油滴是否已经扩展 
    
    //三个函数,感觉这样写可能会比 C++ 自带的快一些 
    inline double Max(double a,double b){
        return a > b ? a : b ;
    }
    inline double Min(double a,double b){
        return a < b ? a : b ;
    }
    inline int Abs(int a,int b){
        if(a>b)
            return a-b;
        return b-a;
    }

    然后就让我们进入真正的重点:搜索函数(代码里有详解哦~~)

    void find(int now,double sum){//now 为将要搜第几个油滴 ,sum为现在已经扩展的面积 
        if(now==n+1){//都搜完了
            ans=Max(ans,sum);//更新答案。 
            return ;
        }
        
        for(int i=1;i<=n;i++)
            if(!b[i]){//若这个油滴还没被扩展 
            
                int tt=0;//临时变量 
                
                for(int j=1;j<=n;j++)//这个循环的作用是判断此油滴是否已经被其他油滴覆盖了 
                    if(b[j]&&r[j]>=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]))){
                        tt=1;
                        b[i]=1;
                        find(now+1,sum); 
                        b[i]=0;
                    }
                    
                if(tt==1)
                    continue ;
                    
                b[i]=1;
                
                r[i]=Min(Abs(x[i],X1),Abs(x[i],X2));
                r[i]=Min(r[i],Min(Abs(y[i],Y1),Abs(y[i],Y2)));//此油滴的可能半径为到边界的最短路径 
                
                for(int j=1;j<=n;j++)//根据已经扩展的油滴(j)半径来确定 此油滴(i)的最小半径 
                    if(i!=j&&b[j]){
                        double d=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
                        r[i]=Min(r[i],d-r[j]);
                    }
                find(now+1,sum+pi*r[i]*r[i]);//寻找下一个油滴
                 
                r[i]=0;//回溯 
                b[i]=0; 
            }
    }

    自此,本题重点就完啦。

    下面是完整代码:

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #define pi 3.1415926
    using namespace std;
    int n; //n个油滴 
    int X1,Y1,X2,Y2;//矩形区域 
    double ans;//覆盖的最大面积 
    
    int x[10],y[10];//编号为 [i] 的油滴的坐标 
    double r[10];   //编号为 [i] 的油滴的半径 
    
    bool b[10]; //记录此油滴是否已经扩展 
    
    //三个函数,感觉这样写可能会比 C++ 自带的快一些 
    inline double Max(double a,double b){
        return a > b ? a : b ;
    }
    inline double Min(double a,double b){
        return a < b ? a : b ;
    }
    inline int Abs(int a,int b){
        if(a>b)
            return a-b;
        return b-a;
    }
    void find(int now,double sum){//now 为将要搜第几个油滴 ,sum为现在已经扩展的面积 
        if(now==n+1){//都搜完了
            ans=Max(ans,sum);//更新答案。 
            return ;
        }
        
        for(int i=1;i<=n;i++)
            if(!b[i]){//若这个油滴还没被扩展 
            
                int tt=0;//临时变量 
                
                for(int j=1;j<=n;j++)//这个循环的作用是判断此油滴是否已经被其他油滴覆盖了 
                    if(b[j]&&r[j]>=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]))){
                        tt=1;
                        b[i]=1;
                        find(now+1,sum); 
                        b[i]=0;
                    }
                    
                if(tt==1)
                    continue ;
                    
                b[i]=1;
                
                r[i]=Min(Abs(x[i],X1),Abs(x[i],X2));
                r[i]=Min(r[i],Min(Abs(y[i],Y1),Abs(y[i],Y2)));//此油滴的可能半径为到边界的最短路径 
                
                for(int j=1;j<=n;j++)//根据已经扩展的油滴(j)半径来确定 此油滴(i)的最小半径 
                    if(i!=j&&b[j]){
                        double d=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
                        r[i]=Min(r[i],d-r[j]);
                    }
                find(now+1,sum+pi*r[i]*r[i]);//寻找下一个油滴
                 
                r[i]=0;//回溯 
                b[i]=0; 
            }
        
    }
    inline int read(){
        int x=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-')
                f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=(x<<1)+(x<<3)+(ch^48);
            ch=getchar();
        }
        return x*f;
    }
    int main(){
        n=read();
        X1=read()+1000,Y1=read()+1000,X2=read()+1000,Y2=read()+1000;
        for(int i=1;i<=n;i++)
            x[i]=read()+1000,y[i]=read()+1000;
            
        find(1,0.0);
        
        ans=Abs(X1,X2)*Abs(Y1,Y2)-ans;
        int answer=int(ans+0.5);
        printf("%d",answer);
        return 0;
    }
  • 相关阅读:
    原生js实现Ajax请求,包含get和post
    JSP和Servlet的关系
    框架、框架模式和设计模式
    Java技术综述
    传输层和网络层区别(形象解释)
    Vue基本用法:过滤器、生命周期钩子函数和利用webpack 生成项目
    Vue基本用法:组件
    Vue基本用法:计算属性、监听器和表单输入绑定
    Vue基本用法:模板语法和指令系统
    win10想说爱你不容易——安装.net3.5也是一个坑(已有完美解决方法)
  • 原文地址:https://www.cnblogs.com/qiuchengrui/p/9785435.html
Copyright © 2020-2023  润新知