zoukankan      html  css  js  c++  java
  • Acwing 180. 排书

    给定 (n) 本书,编号为 1∼n。

    在初始状态下,书是任意排列的。

    在每一次操作中,可以抽取其中连续的一段,再把这段插入到其他某个位置。

    我们的目标状态是把书按照 1∼n 的顺序依次排列。

    求最少需要多少次操作。

    解:

    考虑每一步决策数量,当抽取长度为 (len) 的一段时,有 (n - len+ 1) 种抽法,对于每种抽法,有 (n - len) 种放法。另外,将某一段向前移动,等价于将跳过的那段向后移动,因此每种移动方式被算了两遍,所以每个状态总共的分支数量是:

    [sumlimits_{len = 1}^n cfrac{(n - len + 1) * (n - len)}{2} = cfrac{15*14 + 14*13 + 13*12...+2*1}{2} = 560 ]

    题目要求最多(4)次算出答案,那么就是(560^4),又由于(IDA \,\, star) 有估价函数,那么实际上数据量会更小。

    对于估价函数:答案应该是(1,2,3,4,5...,n)的形式,所以每个数(a[i])的的后边应该是(a[i + 1]),满足(a[i] + 1 = a[i + 1]),不满足就记录一下这种情况的数量(cnt),而我们每操作一次最多可以改变三个位置的地方,即(l(当前段的左边),r(当前段的右边),k(插入的位置))三个位置的顺序,因此最多一次可以改变三个,即终点到当前状态下的预估距离,那么最优情况下我们操作一个序列改变三个,那么估价函数就设置为(f(x) = lceil cfrac{cnt}{3} ceil),如果估价函数 (f(x) = 0),说明序列已经有序。

    考虑(IDA star)(A star)

    (IDA star)是迭代加深和估价函数结合版

    // Problem: 排书
    // Contest: AcWing
    // URL: https://www.acwing.com/problem/content/182/
    // Memory Limit: 64 MB
    // Time Limit: 1000 ms
    // 
    // Powered by CP Editor (https://cpeditor.org)
    
    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 15;
    int n;
    int q[N];
    int w[5][N];
    
    int f() {
        int cnt = 0;
        for (int i = 0; i + 1 < n; i++) {
            if (q[i + 1] != q[i] + 1) cnt++;
        }
        return (cnt + 2) / 3;
    }
    
    bool dfs(int depth, int max_depth) {
        if (depth + f() > max_depth) return false;
        if (f() == 0) return true;
    
        for (int len = 1; len <= n; len++) {
            for (int l = 0; l + len - 1 < n; l++) {
                int r = l + len - 1;
                for (int k = r + 1; k < n; k++) { //把当前区间放到哪个位置上
                    memcpy(w[depth], q, sizeof q);
                    int y = l;
                    for (int x = r + 1; x <= k; x++, y++) q[y] = w[depth][x];
                    for (int x = l; x <= r; x++, y++) q[y] = w[depth][x];
                    if (dfs(depth + 1, max_depth)) return true;
                    memcpy(q, w[depth], sizeof q);
                }
            }
        }
    
        return false;
    }
    
    int main() {
        int t;
        cin >> t;
        while (t--) {
            cin >> n;
            for (int i = 0; i < n; i++) cin >> q[i];
            int depth = 0;
            while (depth < 5 && !dfs(0, depth)) depth++;
            if (depth == 5) puts("5 or more");
            else cout << depth << endl;
        }
        return 0;
    }
    

    (A star)

    注意:

    在哈希表中嵌套结构体的时候需要重载相应的函数,例如哈希函数,所以这里不如直接自己实现哈希函数。

    还要注意堆中嵌套结构体重载一下小于号的方式。

    // Problem: 排书
    // Contest: AcWing
    // URL: https://www.acwing.com/problem/content/182/
    // Memory Limit: 64 MB
    // Time Limit: 1000 ms
    // 
    // Powered by CP Editor (https://cpeditor.org)
    
    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef unsigned long long ULL; 
    
    const int N = 15;
    int n, P = 17;
    int w[5][N];
    
    struct Node {
    	int q[N], step, f;
    	bool operator < (const Node &x) const{
    		return f > x.f;
    	}
    }start;  
    
    //在unordered_set中嵌套结构体还是要重写Hash函数,不如直接这样写
    
    ULL getHash(Node x) {
    	ULL res = 0;
    	for (int i = 0; i < n; i++) {
    		res = res * P + x.q[i];
    	}
    	return res;
    }
    
    int f(Node x) {
    	int cnt = 0;
    	for (int i = 0; i + 1 < n; i++) {
    		if (x.q[i + 1] != x.q[i] + 1) cnt++;
    	}
    	return (cnt + 2) / 3;
    }
    
    int astar() {
            unordered_set<ULL> st;
    	priority_queue<Node> heap;
    	start.step = 0, start.f = f(start);
    	heap.push(start); st.insert(getHash(start));
    	while (heap.size()) {
    		auto t = heap.top();
    		heap.pop();
    		
    		if (t.f >= 5) return 5;
    		if (f(t) == 0) return t.step;
    		
    		for (int len = 1; len <= n; len++) {
    			for (int l = 0; l + len - 1 < n; l++) {
    				int r = l + len - 1;
    				for (int k = r + 1; k < n; k++) {
    					Node v;
    					for (int d = 0; d < n; d++) v.q[d] = t.q[d];
    					int y = l;
    					for (int x = r + 1; x <= k; x++, y++) v.q[x] = t.q[y];
    					for (int x = l; x <= r; x++, y++) v.q[x] = t.q[y];
    					if (st.count(getHash(v))) continue;
    					st.insert(getHash(v));
    					v.step = t.step + 1;
    					v.f = v.step + f(v);
    					heap.push(v); 
    				}
    			}
    		}
    	} 
    	
    	return 5;
    }
    
    int main() {
    	int t;
    	cin >> t;
    	while (t--) {
    		cin >> n;
    		for (int i = 0; i < n; i++) cin >> start.q[i];
    		int res = astar();
    		if (res >= 5) puts("5 or more");
    		else cout << res << endl;
    	}
    	return 0;
    }
    
    
    
    
  • 相关阅读:
    IDEA中用jetty启动项目时,url 404
    Mysql 性能查询
    RabbitMQ 安装
    Ubuntu安装kubernetes
    .net 4 调用WCF时报错 Type 'System.Threading.Tasks.Task`1[]' cannot be serialized
    Windows XP SP2上安装.net 4
    angular学习的一些Mark
    [转]对 td 使用 overflow:hidden; 无效的几点错误认识
    静态方法与非静态方法的区别
    二进制字符串的权限管理
  • 原文地址:https://www.cnblogs.com/ZhengLijie/p/15169219.html
Copyright © 2011-2022 走看看