目录
使用同样的本地知识库,使用相同的提问词,在IMA环境中,选择混元和DeepSeek,会有什么样不同的体验呢?
一、提问词
请提供信息奥赛2008年提高组传纸条的题解,要求:
1、从文件“message.in”读数据,答案写入文件“message.out”。
2、不使用C++11以后版本的语法规则。
3、解释题解中的主要算法。
二、IMA+混元
2008年信息奥赛提高组传纸条题解
【题目描述】
题目要求在一个二维网格中找到两条不交叉的路径,使得路径上的数字之和最大。路径从左上角 (1, 1)
出发,到达右下角 (m, n)
。路径上的每个格子只能走一次。
【解题思路】
此问题可以通过动态规划来解决。我们定义一个四维数组 f[i][j][k][l]
表示从 (0, 0)
位置出发,通过两条不交叉的路径到达 (i, j)
和 (k, l)
的最大数字之和。
【动态规划方程】
动态规划的转移方程为:
$$F[i][j][k][l] = \max \{ F[i-1][j][k-1][l], F[i-1][j][k][l-1], F[i][j+1][k-1][l], F[i][j+1][k][l-1] \} + G[i][j] + G[k][l]$$
其中,G[i][j]
是网格中 (i, j)
位置的数字。
【优化】
通过观察可以发现,纸条传的横坐标加纵坐标等于走的步数,即 l = i + j - k
(当 l > 0
)。利用这个关系可以将四维数组降维到三维数组,从而降低时间复杂度。
【实现代码】
#include<stdio.h>
#include<stdlib.h>
int f[52][52][52] = {0}, n, m;
int G[52][52];
int max(int a, int b, int c, int d) {
if (a < b) a = b;
if (a < c) a = c;
if (a < d) a = d;
return a;
}
int main() {
freopen("message.in", "r", stdin);
freopen("message.out", "w", stdout);
scanf("%d%d", &m, &n);
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
scanf("%d", &G[i][j]);
}
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
for (int k = 1; k <= m; k++) {
int l = i + j - k;
if (l > 0 && l <= n) {
f[i][j][k] = max(f[i-1][j][k-1], f[i-1][j][k], f[i][j-1][k-1], f[i][j-1][k]) + G[i][j] + G[k][l];
if (i == k && j == l) {
f[i][j][k] -= G[i][j]; // 避免重复计算
}
}
}
}
}
printf("%d\n", f[m][n][m]);
return 0;
}
【解释】
- 输入输出:程序从文件
message.in
读取数据,并将结果写入文件message.out
。 - 初始化:使用一个三维数组
f
来存储动态规划的状态,初始值为0。 - 读取网格:读取网格的大小
m
和n
,以及每个格子的数字。 - 动态规划:通过三层循环遍历所有可能的路径组合,计算并更新状态。
- 输出结果:最终输出
f[m][n][m]
,即从左上角到右下角的最大数字之和。
通过这种方式,我们可以有效地解决传纸条问题,并确保路径不交叉。
三、IMA+DeepSeek
根据提供的文档内容,以下是2008年信息奥赛提高组传纸条问题的题解:
【题解】
算法核心:多进程动态规划
核心思路:将问题转化为同时运行两个纸条从起点到终点的路径,定义 f[i][j][k][l]
为两个纸条分别到达 (i,j)
和 (k,l)
时的最大价值和。通过优化步数关系 i + j = k + l
(路径同步性质),将状态压缩为三维。
【实现代码(C语言)】
#include<stdio.h>
#include<stdlib.h>
int f[52][52][52][52] = {0}, G[52][52];
int max(int a, int b, int c, int d) {
if (a < b) a = b;
if (a < c) a = c;
if (a < d) a = d;
return a;
}
int main() {
freopen("message.in", "r", stdin);
freopen("message.out", "w", stdout);
int m, n;
scanf("%d%d", &m, &n);
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++)
scanf("%d", &G[i][j]);
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++)
for (int k = 1; k <= m; k++) {
int l = i + j - k;
if (l < 1 || l > n) continue;
f[i][j][k][l] = max(
f[i-1][j][k-1][l],
f[i-1][j][k][l-1],
f[i][j-1][k-1][l],
f[i][j-1][k][l-1]
) + G[i][j] + G[k][l];
if (i == k && j == l)
f[i][j][k][l] -= G[i][j]; // 去重
}
printf("%d\n", f[m][n][m][n]);
return 0;
}
【代码说明】
-
输入输出
使用freopen
从message.in
读取输入,结果写入message.out
。 -
动态规划状态定义
四维数组f[i][j][k][l]
表示两个纸条分别到达(i,j)
和(k,l)
时的最大值。
由于两条路径必须同步(每步移动距离相同),通过l = i + j - k
消去第四维度,时间复杂度降至 $O(n^3)$。 -
状态转移
当前状态的最优值由四种先前状态转移而来:- 纸条1向下,纸条2向下
- 纸条1向下,纸条2向右
- 纸条1向右,纸条2向下
- 纸条1向右,纸条2向右
转移后需加上当前格子的值G[i][j]
和G[k][l]
。
-
路径去重
若两纸条走到同一格子(i,j)
且(k,l)
,需扣除重复计算的数字(f[i][j][k][l] -= G[i][j]
)。
【算法分析】
- 时间复杂度:O(mn(m+n)),适配题目数据规模。
- 空间复杂度:O(m^2 ╳ n^2),通过四维数组保存状态。实际因降维优化,循环后等效为三维操作。
- 关键优化:利用步数同步性简化状态转移,避免暴力枚举所有四维情况。
三、说明
1、DeepSeek模式有推理分析过程,由于不能复制,不方便截图,故未展示。
2、两段代码都通过了Cena评测。