2021-08-24

本文介绍如何使用动态规划解决9个机器人在3x3方格中,经过n步后达到每个格子恰好一个机器人的问题。通过优化dp转移,借助矩阵快速幂技巧,降低了时间复杂度,适用于大规模数据。关键步骤包括初始化状态转移矩阵、计算dp数组和最终的 dfs 走法计数。
摘要由CSDN通过智能技术生成

题目描述

9 个机器人,在 3 * 3 的方格里,一开始 9 个机器人分别站在 9 个格子上,每一步机器人可
以往临近的一个格子移动或留在原地(同一个格子可以有多个机器人停留),经过 n 步后有
多少种不同的走法,使得每个格子上都有 1 机器人停留。由于方法数量巨大,输出 Mod
10^9 + 7 的结果。

输入输出格式

输入格式

第一行包含一个整数 n。

输出格式

输出一行输出走法的数量 Mod 10^9 + 7

数据范围

对于 40%的数据,1 <= n<= 10;
对于 70%的数据,1 <= n <= 10^6;
对于 100%的数据,1 <= n <= 10^18。

样例

样例一输入:

1

样例一输出:

299

思路

1.40%数据

暴力
期望复杂度 Θ ( 玄 学 ) \Theta \left( 玄学 \right) Θ()

2.70%数据

考虑dp
dp[i][j][k] 表示走了i步,起点在j终点在k的方案数
dfs枚举全排列
期望复杂度 Θ ( 81 n ) \Theta \left( 81n \right) Θ(81n)

3.100%数据

考虑优化dp转移
很明显一个点朝其他点转移的状态量小且固定
利用矩阵快速幂优化掉n
期望复杂度 Θ ( 9 3 log ⁡ n ) \Theta ( 9^{3} \log n ) Θ(93logn)

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <list>
#include <map>
 
#define ll long long
#define ull unsigned long long

using namespace std;
const int mod = 1e9+7;
int dp[10][10];
bool mp[10];
ll n,ans;
ll e[10][10] = {
    {0,0,0,0,0,0,0,0,0,0},
    {0,1,1,0,1,0,0,0,0,0},
    {0,1,1,1,0,1,0,0,0,0},
    {0,0,1,1,0,0,1,0,0,0},
    {0,1,0,0,1,1,0,1,0,0},
    {0,0,1,0,1,1,1,0,1,0},
    {0,0,0,1,0,1,1,0,0,1},
    {0,0,0,0,1,0,0,1,1,0},
    {0,0,0,0,0,1,0,1,1,1},
    {0,0,0,0,0,0,1,0,1,1},
};

struct mat {
    ll p[10][10];
    mat(){memset(p,0,sizeof(p));}
    void cl() { for(int i=1;i<=9;i++) p[i][i]=1;}
    mat operator * (const mat&a)const {
        mat tmp;
        for(int k = 1; k <= 9; k++)
            for(int i = 1; i <= 9; i++)
                for(int j = 1; j <= 9; j++) {
                    tmp.p[i][j] += p[i][k] * a.p[k][j];
                    if(tmp.p[i][j] >= mod) tmp.p[i][j] %= mod;
                }
        return tmp;
    }
}XJH;

inline void Init() {
    memcpy(XJH.p,e,sizeof e);
}

mat ksm(mat bs,ll x) {
    mat ans;
    ans.cl();
    while(x) {
        if(x & 1) ans = ans * bs;
        bs = bs * bs;
        x >>= 1;
    }
    return ans;
}

void dfs(int step,ll sum) {
    if(step == 10) {
        ans += sum;
        if(ans >= mod) ans %= mod;
        return;
    }
    for(int i = 1; i <= 9; i++)
        if(!mp[i]) {
            mp[i] = 1;
            dfs(step+1,(sum * dp[i][step])%mod);
            mp[i] = 0;
        }
}

int main() {
    // freopen("B.in","r",stdin);
    // freopen("B.out","w",stdout);
    Init();
    scanf("%lld",&n);
    mat bs = ksm(XJH,n);
/*
    for(int i = 0; i <= 9; i++)
        for(int j = 0; j <= 9; j++)
            if(j == 9) cout << bs.p[i][j] << endl;
            else cout << bs.p[i][j] << ' ' ;
*/
    for(int i = 1; i <= 9; i++) {
        mat tmp;
        tmp.p[1][i] = 1;
        tmp = tmp*bs;
        for(int j = 1; j <= 9; j++)
            dp[i][j] = tmp.p[1][j];
    }
    dfs(1,1);
    printf("%lld",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这段代码存在一些语法错误。具体来说: 1. `console.log` 方法中的字符串应该使用引号括起来,例如 `"每页 ${val} 条"` 和 `"当前页: ${val}"`。 2. `toggleContent` 方法应该定义在 `methods` 对象中,并且缺少一个左大括号 `{`。 3. `toggleContent` 方法中的 `console.log` 方法没有使用正确的字符串格式化,应该使用反引号括起来,并在占位符 `${}` 中使用变量名,例如 ``console.log(`当前高度: ${content.style.height}`)``。 4. 在 `v-for` 指令中,应该使用 `v-bind:key` 显式地绑定 `tableData` 数组中每个对象的唯一标识符,例如 `v-for="(item, index) in tableData" v-bind:key="item.number"`。 下面是修正后的代码: ``` <script> let v = new Vue({ el: '#app', data: { value1: '', value2: '', pickerOptions: { shortcuts: [ { text: '今天', onClick(picker) { picker.$emit('pick', new Date()); } }, { text: '昨天', onClick(picker) { const date = new Date(); date.setTime(date.getTime() - 3600 * 1000 * 24); picker.$emit('pick', date); } }, { text: '一周前', onClick(picker) { const date = new Date(); date.setTime(date.getTime() - 3600 * 1000 * 24 * 7); picker.$emit('pick', date); } } ] }, tableData: [ { number: '1', date: '2021-08-01' }, { number: '2', date: '2021-08-01' }, { number: '3', date: '2021-08-01' }, { number: '4', date: '2021-08-01' }, { number: '5', date: '2021-08-01' }, { number: '6', date: '2021-08-01' }, { number: '7', date: '2021-08-01' }, { number: '8', date: '2021-08-01' } ], currentPage1: 5, currentPage2: 5, currentPage3: 5, currentPage4: 4 }, methods: { deleteRow(index, rows) { rows.splice(index, 1); }, handleSizeChange(val) { console.log(`每页 ${val} 条`); }, handleCurrentChange(val) { console.log(`当前页: ${val}`); }, toggleContent() { var content = document.getElementById("content"); var btn = document.getElementById("toggle-btn"); if (content.style.height === "100px") { content.style.height = "auto"; btn.innerHTML = "收起"; } else { content.style.height = "100px"; btn.innerHTML = "展开"; } console.log(`当前高度: ${content.style.height}`); } } }); </script> <table> <thead> <tr> <th>序号</th> <th>日期</th> <th>操作</th> </tr> </thead> <tbody> <tr v-for="(item, index) in tableData" v-bind:key="item.number"> <td>{{ item.number }}</td> <td>{{ item.date }}</td> <td><button @click="deleteRow(index, tableData)">删除</button></td> </tr> </tbody> </table> <div class="pagination"> <el-pagination background layout="sizes, prev, pager, next, jumper" :current-page.sync="currentPage1" :page-sizes="[5, 10, 20]" :page-size="5" @size-change="handleSizeChange" @current-change="handleCurrentChange" :total="tableData.length" ></el-pagination> </div> <div id="content" style="overflow: hidden; height: 100px;"> 这是一段需要展开的内容。 </div> <button id="toggle-btn" @click="toggleContent">展开</button> ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值