很有难度!!----全国计算机奥赛压轴试题

stephen85 2003-10-18 09:18:54
问题描述:
  设有N*N的方格图(N<=8),我们将其中的某些方格中填入正整数,二其他的方格中则放入数字0。如下图所示(见样例):
   ->向右
A
0 0 0 0 0 0 0 0
0 0 13 0 0 6 0 0
0 0 0 0 7 0 0 0
0 0 0 14 0 0 0 0
0 21 0 0 0 5 0 0
0 0 15 0 0 0 0 0
0 14 0 0 0 0 0 0
0 0 0 0 0 0 0 0 B

  某人从图的左上角的A点出发,可以向下行走,也可以向右走,知道到达右下角的B点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。
  此人从A点到B点共走两次,试找出2条这样的路径,使得取得的数之和为最大。
输入:
  输入的第一行为一个整数N(表示N*N的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的0表示输入结束。
输出:
  只需输出一个整数,表示2条路径上取得的最大的和。
样例:
输入
8
2 3 13
2 6 6
3 5 7
4 4 14
5 2 21
5 6 4
6 3 15
7 2 14
0 0 0
输出
67
...全文
224 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
one_add_one 2003-10-19
  • 打赏
  • 举报
回复
这个题可以直接用DP,复杂度是O(n^3)
不过比较难想...

上面的程序就用的这种方法..


也可以用搜索+DP...复杂度高一点...
one_add_one 2003-10-19
  • 打赏
  • 举报
回复
/*
Problem 4
Written by one_add_one (December 2 2000)
Email: one_add_one @163.net
*/
#include <stdio.h>
#define MAX 50

int max(int a,int b){
if (a>b) return a;else return b;
}

main(){
int pa[MAX][MAX],pb[MAX][MAX],p[MAX][MAX];
int n,i,j,k;
int *a=&pa[0][0],*b=&pb[0][0],*swap;
for (j=0;j<MAX;j++)
for (i=0;i<MAX;i++)
p[j][i]=0;
printf("Input:");scanf ("%d",&n);
for (j=0;j<MAX;j++)
for (i=0;i<MAX;i++)
*(a+j*MAX+i)=*(b+j*MAX+i)=0;
do{
printf(">");scanf("%d %d %d",&i,&j,&k);
p[i][j]=k;
}
while(i!=0 || j!=0 || k!=0);
for (j=1;j<=n;j++)
for (i=j;i<=n;i++){
*(a+j*MAX+i)=*(a+MAX+i-1)+p[1][i];
}
for (k=2;k<=n;k++){
for (j=1;j<=n;j++)
for (i=j;i<=n;i++){
if (j==1) *(b+j*MAX+i)=*(a+j*MAX+i)+p[k][1];
else *(b+j*MAX+i)=max(*(a+j*MAX+i),*(b+(j-1)*MAX+i))+p[k][j];
}
swap=a;a=b;b=swap;
for (j=1;j<=n;j++)
for (i=j;i<=n;i++){
if (i==1) *(b+j*MAX+i)=*(a+j*MAX+i);
else{
if (j==i) *(b+j*MAX+i)=max(*(b+(j-1)*MAX+i),*(a+j*MAX+i));
else *(b+j*MAX+i)=max(*(b+j*MAX+i-1),*(a+j*MAX+i))+p[k][i];
}
}
swap=a;a=b;b=swap;
}
printf("%d\n",pa[n][n]);
}
nuaabestbo 2003-10-19
  • 打赏
  • 举报
回复
除了找出最优解外,还可将所有路径输出!
nuaabestbo 2003-10-19
  • 打赏
  • 举报
回复
BFS+DP
nuaabestbo 2003-10-19
  • 打赏
  • 举报
回复
#include <stdio.h>
#include <stdlib.h>

int n=0,mmax,result=0,a[64][3],path[16],p1[16],p2[16],*b,**ff;
//f:use in getmax2
//ff:use through the program
//mmax:temporary max through the program;
//result:the final max;
void error()
{
printf("Alloc Memory Error!");
exit(1);
}

void print()
{
int i;

printf("Path 1:\n%d",p1[1]);
for(i=2;i<=p1[0];i++) printf("--%d",p1[i]);
printf("\nPath 2:\n%d",p2[1]);
for(i=2;i<=p2[0];i++) printf("--%d",p2[i]);
printf("\nMAX=%d\n",result);
}

void getmax2(int k)
{
int next,i,j,max,**f,t=0;
//max:temporary in getmax2
f=(int **)malloc(sizeof(int *)*n);
for(i=0;i<n;i++)
{
f[i]=(int *)malloc(sizeof(int)*2);
if(!f[i]) error();
}
for(i=0;i<n;i++)
if(b[i])
{
f[i][0]=a[i][2];
f[i][1]=0;
}
for(i=n-2;i>=0;i--)
if(b[i])
{
max=0;
next=0;
for(j=i+1;j<n;j++)
if(b[j] && f[j][0]>max && a[j][0]>=a[i][0] && a[j][1]>=a[i][1])
{
max=f[j][0];
next=j;
}
if(next)
{
f[i][0]+=max;
f[i][1]=next;
}
}
max=0;next=0;
for(i=0;i<n;i++)
if(max<f[i][0] && b[i])
{
max=f[i][0];
next=i;
}
mmax+=max;
if(mmax>result)
{
result=mmax;
p1[0]=k+1;
for(i=0;i<=k;i++) p1[i+1]=path[i];
while(f[next][1])
{
p2[++t]=next;
next=f[next][1];
}
p2[t+1]=next;
p2[0]=t+1;
//print();//在此加入print(),可打印整个搜索过程
}
for(i=0;i<n;i++) free(f[i]);
free(f);
}

void calmax(int kk)
{
int i;

mmax=0;
for(i=0;i<=kk;i++) mmax+=a[path[i]][2];
getmax2(kk);
}

void produceff()
{
int i,j,temp;

for(i=0;i<=n-1;i++)
{
temp=0;
for(j=i+1;j<n;j++)
if(a[j][0]>=a[i][0] && a[j][1]>=a[i][1])
temp++;
ff[i]=(int *)malloc(sizeof(int)*(temp+1));
if(!ff[i]) error();
ff[i][0]=temp; //save the total number
temp=0;
for(j=i+1;j<n;j++)
if(a[j][0]>=a[i][0] && a[j][1]>=a[i][1])
ff[i][++temp]=j;
}
}

void find(int k)//BFS
{
int i;

calmax(k);
for(i=1;i<=ff[path[k]][0];i++)
{
k++;
path[k]=ff[path[k-1]][i];
b[path[k]]=0;
find(k);
b[path[k]]=1;
k--;
}
}

void main()
{
FILE *file;
int x,y,i,j;
//read data
file=fopen("xt4.txt","r");
if(!file) {printf("File Open Error!");exit(1);}
fscanf(file,"%d",&x);
fscanf(file,"%d",&x);
while(x)
{
a[n][0]=x;
fscanf(file,"%d%d",&x,&y);
a[n][1]=x;a[n][2]=y;
n++;
fscanf(file,"%d",&x);
}
fclose(file);
//initialize
b=(int *)malloc(sizeof(int)*n);
ff=(int **)malloc(sizeof(int *)*n);
if(!b||!ff) error();
//getmax=max{every1+getmax2}
produceff();
for(i=0;i<n;i++)
{
for(j=0;j<n;j++) b[j]=1;
path[0]=i;
b[i]=0;
find(0);
}
print();
//destroy
free(b);
for(i=0;i<n;i++) free(ff[i]);
free(ff);
}
CD2006 2003-10-19
  • 打赏
  • 举报
回复
小提示:
在将matrix划分后,
对任一点(x,y)都有: y=k+1-x (k为当前阶段值)
CD2006 2003-10-19
  • 打赏
  • 举报
回复
第k 个阶段,即为从(1,k)到(k,1)
的右下对角线。
设第k个阶段的A(x1,y1), B(x2,y2)两个节点,
那么从(1,1)到A(x1,y1)有很多路径path(A),到B(x2,y2)也有很多路径path (B),
虽然路多,组合多,但max{path(A)+path(B)} 的值只有一个,这个值即是我们要用动态规划法
探索得到并保存的,所以此题关键在于:在第k 个阶段,找出关于任意两点A,B的max值。
(注意是任意两点A,B,且A,B可相同!!!)

步步推进,即可搜出最后解。

设maxpathes[k][A][B] 为在第k阶段,两条路径分别行至A和B两节点的最大路径和
递推公式如下:
k=1 maxpathes[1][(1,1)][(1,1)]=0;
k>=2 maxpathes[k][A][B]={ MAX { maxpathes[k-1][A*][B*]+A格上的值 | if A=B},
MAX { maxpathes[k-1][A*][B*]+A格上的值+B格上的值 | if A<>B}}

A* 属于 可达A的节点集合,B* 属于 可达B的节点集合
CD2006 2003-10-19
  • 打赏
  • 举报
回复
Dymatic Programming:
每走一步一个状态, 这样一个matrix被分为2n-1个阶段。

stephen85 2003-10-18
  • 打赏
  • 举报
回复
哪位高手能给个伪代码?
谢谢!!
stephen85 2003-10-18
  • 打赏
  • 举报
回复
英语有点菜,
如何将广度优先与动态规划结合起来呢?
此题关键要求两条路径之和最大,动态规划的最优解递推公式如何呢?
levinjoe 2003-10-18
  • 打赏
  • 举报
回复
DP 动态规划!自己多看看书吧!
stephen85 2003-10-18
  • 打赏
  • 举报
回复
何为DP呢?
敢请高人再指点迷津,此题对我非常重要,谢谢!!!!
kbsoft 2003-10-18
  • 打赏
  • 举报
回复
记忆化搜索=搜索的形式+DP思想。
这题最好用BFS+DP
stephen85 2003-10-18
  • 打赏
  • 举报
回复
何为记忆化搜索?请高人不吝赐教.
在下洗耳恭听,万分感谢!
kbsoft 2003-10-18
  • 打赏
  • 举报
回复
又是方格取数! 记忆化搜索

33,008

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧