zoukankan      html  css  js  c++  java
  • [无聊测试赛] T9 矩阵覆盖

    这道题是神题,但是数据水,所以可以用一个很玄学的dp水过去

    第一,这道题的数据没有k=4的数据. 第二,这题的所有数据中最优解的矩形要么是上下,要么左右(但其他数据会有不同的情况)

    知道了这个以后,我们可以将 (x)(y) 分别排序一次,然后用dp求解

    这里的dp用三维. (i,j,k) 分别表示所用的矩阵数量,上一个矩阵的id和现在矩阵的id. (dp[i][j][k]) 里存的就是在这种情况所能拿到的最小值

    开始我们先将使用一个矩阵的最小值统计出来,然后dp再慢慢找用第二个矩阵代替所能取到的值.

    怎么求一个矩阵的覆盖面积呢? 答案就是底乘高,也就是从 (j-k) 之间的 ((max x - min x) * (max y - min y)).这个操作可以用四个线段树来实现

    而求第i个矩阵所覆盖的面积就是 (max (dp[i][j][k], dp[i-1][j][u] + num[u+1][k])). 其中 (u in{(1,j-1)}) ,而 (num[i][j]) 等同于 (dp[1][i][j]).

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <math.h>
    using namespace std;
    #define pp pair<int,int>
    #define f first
    #define s second
    #define mid (l+r)/2
    #define lson (way<<1)
    #define rson (way<<1)+1
    const int MAXN = 55;
    int n,k,dp[5][MAXN][MAXN],num[MAXN][MAXN],seg[MAXN*4][5],ans = 1e9;
    pp pos[MAXN];
    inline bool sorted_x(pp a, pp b){
      return a.f<b.f || (a.f==b.f && a.s<b.s);
    }
    inline bool sorted_y(pp a, pp b){
      return a.s<b.s || (a.s==b.s && a.f<b.f);
    }//排序
    inline int fxy(int way, int l, int r, int qlow, int qhigh, int type){//fxy就是query
      if (qlow<=l && r<=qhigh) return seg[way][type];
      if (qlow>r || qhigh<l) return 1e9*pow(-1,type);//pow是因为取最大值时如果发现答案不在范围内要输出最小值,反之输出最大
      int le = fxy(lson,l,mid,qlow,qhigh,type);
      int ri = fxy(rson,mid+1,r,qlow,qhigh,type);
      return ((type%2) ? max(le,ri) : min(le,ri));//type%2的意思是type 1,3 为求最大值, 2,4为求最小值. %2找现在的状态
    }
    inline void make_tree(int type, int way, int l, int r){//建树
      if (l==r){
        seg[way][type] = (type>2) ? pos[l].s : pos[l].f;
        return;
      }
      make_tree(type,lson,l,mid);
      make_tree(type,rson,mid+1,r);
      seg[way][type] = (type%2) ? max(seg[lson][type],seg[rson][type]) : min(seg[lson][type],seg[rson][type]);
    }
    inline void find_ans(){
      memset(dp,0x3f3f,sizeof(dp));
      for (int i=1;i<=4;i++) make_tree(i,1,1,n);//建四棵树
      for (int i=1;i<=n;i++){
        for (int j=i+1;j<=n;j++){
          num[i][j] = dp[1][i][j] = (fxy(1,1,n,i,j,1)-fxy(1,1,n,i,j,2)) * (fxy(1,1,n,i,j,3)-fxy(1,1,n,i,j,4));//一个矩形
        }
      }
      // for (int i=1;i<=n*4;i++) cout << seg[i][4] << " ";
      for(int i=2;i<=k;i++){
        for(int j=1;j<=n;j++){
          for(int l=j+1;l<=n;l++){
            for(int u=j;u<l;u++)
            dp[i][j][l]=min(dp[i][j][l],dp[i-1][j][u]+num[u+1][l]);//转移
          }
        }
      }
      ans = min(ans,dp[k][1][n]);//答案就是用了k个矩形从1覆盖到n的最小值
    }
    int main(){
      cin >> n>>k;
      for (int i=1;i<=n;i++) cin >> pos[i].f >> pos[i].s;
      sort(pos+1,pos+n+1,sorted_x);
      find_ans();
      sort(pos+1,pos+n+1,sorted_y);
      find_ans();
      cout << ans;
    }
    
  • 相关阅读:
    【彩彩只能变身队】(迟到的)团队介绍
    【彩彩只能变身队】用户需求分析(二)—— 调查结果
    【彩彩只能变身队】用户需求分析(一)—— 调查问卷
    C语言I博客作业04
    C语言I博客作业06
    c语言1作业07
    C语言I博客作业03
    C语言I博客作业02
    C语言I博客作业05
    【OpenGL编程指南】之投影和视口变换
  • 原文地址:https://www.cnblogs.com/DannyXu/p/12538577.html
Copyright © 2011-2022 走看看