zoukankan      html  css  js  c++  java
  • Codeforces #576 Rectangle Painting 1 | div1D | div2F | DP | Rustlang

    原题链接

    大意

    n*n正方形 有黑有白

    每次可以选择一个 矩形把它全变成白色,代价是max(长,宽)

    求吧 整个正方形 全变白 的最小代价

    数据范围

    n <= 50

    题解

    首先如果 我们刷了两个有相邻边或重叠的 白色矩形

    那么 假设他们的代价分别为 x和y

    那么 一定有 一个 边长为x+y的正方形 完全覆盖了这两个白色矩形

    dis|row| <= rowX+roxY <= costX+costY = x+y

    dis|col| <= colX+roxY <= costX+costY = x+y

    所以综上所述 两两不重叠

    再来,证明 如果 最优结果要么选择的单一矩形,要么一定能 垂直 或水平分化,即是 不会出现类似 弦图 这样的分化

    假设存在,那么意味这有n*m的矩形,和对应选择多个图画方案,使得

    1. 图画方案是最优的
    2. 子选择矩形个数大于1
    3. 不存在按竖着 分化,或横着分化,使得子选择被分开

    对于横向来看,意味着任意选择分割线 都会和最优解的选择中的矩形的横着的边冲突,

    也就意味着,从min横向点 到 max横向点,所有点都有边。

    即是,从横向看 最优解的 cost 横向 >= (max横向点-min横向点)

    由对称性,从纵向看 最优解的 cost 纵向 >= (max纵向-min纵向点)

    那么我们直接用 相应的大矩形(max横向点-min横向点,max纵向-min纵向点) 从面积上覆盖 最优解答

    大矩形 cost (从覆盖关系,和最优解答定义)>= 最优解答cost (根据横向和纵向边的关系)>= 大矩形cost

    综上

    1. 没有重叠 至多相邻
    2. 要么 单一选择的矩形(如大矩形),要么可纵向 或 可横向分割

    所以

    dp[top i0 -> bottom i1][left j0 -> right j1]
    =min(
      max(i1-i0,j1-j0),
      dp[i0 -> k][j0->j1] + dp[k+1->i1][j0->j1],
      dp[i0 -> i1][j0 -> k] + dp[i0->i1][k+1->j1],
    )
    

    时间复杂度 O(枚举长 * 枚举宽 * 枚举左上角坐标 * 状态转移) = O(n * n * (n * n) * n) = O(n^5)

    能过

    代码 Rust

    920ms/1s 强行 过了,慢应该是用Vec的原因,如果换成c++的直接数组的话,应该能快很多,// 我暂时还没玩会Rust的多维数组

    CODE URL

    #![allow(unused_imports)]
    use std::cmp::*;
    use std::collections::*;
    
    struct Scanner {
       buffer : std::collections::VecDeque<String>
    }
    
    impl Scanner {
    
       fn new() -> Scanner {
          Scanner {
             buffer: std::collections::VecDeque::new()
          }
       }
    
       fn next<T : std::str::FromStr >(&mut self) -> T {
    
          if self.buffer.len() == 0 {
             let mut input = String::new();
             std::io::stdin().read_line(&mut input).ok();
             for word in input.split_whitespace() {
                self.buffer.push_back(word.to_string())
             }
          }
    
          let front = self.buffer.pop_front().unwrap();
          front.parse::<T>().ok().unwrap()
       }
    }
    
    fn main() {
        let mut s = Scanner::new();
        let n : usize = s.next();
        // dp[top i][left j][bottom i][right j] 全部清理 需要的最小代价
        let mut dp = vec![vec![vec![vec![0;n+1];n+1];n+1];n+1];
        for i in 0..n {
            let line:String = s.next();
            for (j, ch) in line.chars().enumerate() {
                if ch == '#' {
                    dp[i][j][i][j] = 1;
                }
            }
        }
        // 枚举 矩形大小从小到大
        for i in 0..n {
            for j in 0..n {
                if i == 0 && j == 0 {
                    continue;
                }
                // 枚举 矩形左上角坐标
                for p in 0..n-i {
                    for q in 0..n-j {
                        // 右下角坐标
                        let (x,y) = (i+p,j+q);
                        dp[p][q][x][y] = max(i,j)+1;
                        for k in p..x {
                            dp[p][q][x][y]=min(dp[p][q][x][y],dp[p][q][k][y]+dp[k+1][q][x][y]);
                        }
                        for k in q..y {
                            dp[p][q][x][y]=min(dp[p][q][x][y],dp[p][q][x][k]+dp[p][k+1][x][y]);
                        }
                    }
                }
            }
        }
        println!("{}",dp[0][0][n-1][n-1]);
    }
    
  • 相关阅读:
    写在连载之前——DIY微型操作系统篇
    footer始终在页面最底部的方法(问题待检验)
    各种二级菜单代码
    复选框已经有checked,但是页面没有选中效果(解决)
    px em rem 的区别
    marquee标签详解
    Docker:正常运行的容器突然端口不通一般检查方法
    linux中 vm.overcommit_memory 的含义
    redis6 redis-cli cluster的使用总结
    利用Java反射机制优化简单工厂设计模式
  • 原文地址:https://www.cnblogs.com/CroMarmot/p/11279558.html
Copyright © 2011-2022 走看看