题解 P1034 【矩形覆盖】

这么好(shui)的题目怎么能不上随机化搜索呢

//思路:随机化搜索+贪心(从今年D1可以看出贪心是多么重要的能力(然而D1AK也救不了我D2爆炸QAQ(事实证明D2还是多打暴力为上策)))
//每次以一定的概率进行贪心选择或随机选择
//贪心策略为将这个点加入一个矩形,选择代价最小的一个(很明显是错的,所以要随机化搜索辅助)
#include<bits/stdc++.h>
using namespace std;
int ans=2000000000;
int n,k;
struct lj
{
    int x,y;    
}point[59];
int x[5],xx[5],y[5],yy[5];//万能头不能用y1,所以就叫y,yy吧ovo
int main()
{
    srand(time(0));
    scanf("%d %d",&n,&k);
    for(int i=1;i<=n;++i)
    {
        scanf("%d %d",&point[i].x,&point[i].y);    
    }
    for(int iii=1;iii<=250000;++iii)
    {
        srand(rand());//其实没用哦0.0
        random_shuffle(point+1,point+n+1);//随机序列,左闭右开
            for(int j=1;j<=k;j++)//初始化,每个矩阵里至少要有一个点,也是为什么要随机化序列的原因之一
            {
                x[j]=xx[j]=point[j].x;
                y[j]=yy[j]=point[j].y;
            }
            for(int j=k+1;j<=n;j++)
            {
                int mn=2000000000,cs;
                if(rand()%100+1<=70)//以70%的概率选择贪心,似乎70—90的概率都能过
                {
                    for(int ii=1;ii<=k;ii++)
                    {
                        if((max(xx[ii],point[j].x)-min(x[ii],point[j].x))*(max(yy[ii],point[j].y)-min(y[ii],point[j].y))-(xx[ii]-x[ii])*(yy[ii]-y[ii])<mn)
                        {
                            mn=(max(xx[ii],point[j].x)-min(x[ii],point[j].x))*(max(yy[ii],point[j].y)-min(y[ii],point[j].y))-(xx[ii]-x[ii])*(yy[ii]-y[ii]);
                            cs=ii;
                        }
                    }
                }
                else cs=rand()%k+1;//不然随机

           //改变被选择的矩形的大小
                xx[cs]=max(xx[cs],point[j].x);
                x[cs]=min(x[cs],point[j].x);
                yy[cs]=max(yy[cs],point[j].y);
                y[cs]=min(y[cs],point[j].y);
            }
            int tot=0;
            for(int i=1;i<=k;i++)
            {
                tot+=(xx[i]-x[i])*(yy[i]-y[i]);//统计答案    
            }
            for(int i=1;i<k;i++)
            {
                for(int j=i+1;j<=k;j++)
                {
                    if((x[i]==x[j]||x[i]==xx[j]||xx[i]==x[j]||xx[i]==xx[j])&&(y[i]==y[j]||y[i]==yy[j]||yy[i]==y[j]||yy[i]==yy[j]))    tot=200000000;//判断顶点重合
                    if((x[i]==x[j]||x[i]==xx[j]||xx[i]==x[j]||xx[i]==xx[j])&&((y[i]<yy[j]&&yy[i]>y[j])||(y[j]<yy[i]&&yy[j]>y[i])))  tot=200000000;//纵边重合
                    if((y[i]==y[j]||y[i]==yy[j]||yy[i]==y[j]||yy[i]==yy[j])&&((x[i]<xx[j]&&xx[i]>x[j])||(x[j]<xx[i]&&xx[j]>x[i])))  tot=200000000;//横边重合
                }
            }
            ans=min(ans,tot);
    }
    cout<<ans;
    return 0;
}

突然发现自己唯二的题解都是些奇奇怪怪的算法呢…
请大家尽情hack吧ovo


 上一篇
题解 P1908 【逆序对】 题解 P1908 【逆序对】
离散化多麻烦啊,还不如动态开点代码解释在注释里QAQ //思路:运用权值动态开点线段树从后往前扫每次加上比自己小的且编号靠后的点的个数的贡献(由于从后往前扫可以无视编号) 空间&时间:nlogn #include <bits/
2019-02-21
下一篇 
政治正确的睡前故事(4则)【搬运】【破事水】 政治正确的睡前故事(4则)【搬运】【破事水】
(零)很久以前,曾经有一个名叫小红帽的孩子,生活在大森林的边上,大森林里充满了濒临灭绝的猫头鹰和珍稀植物,如果有人愿意花时间研究它们,就会发现癌症的治疗方法。 小红帽和一位称为母亲的养育者一起生活,尽管这并不意味着她们有一个密切的生物学上的
2019-02-21