算法题,求解!

Yoon_EunHae 2008-05-22 05:03:56
问题描述:
  设有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

这是个多进程Dp的题 求C/C++ 实现码
...全文
396 30 打赏 收藏 转发到动态 举报
写回复
用AI写文章
30 条回复
切换为时间正序
请发表友善的回复…
发表回复
qyjubriskxp 2008-10-12
  • 打赏
  • 举报
回复
多进程,DP,好复杂!!!
cqqqq 2008-05-26
  • 打赏
  • 举报
回复
用 "动态规划 .!" 和我的代码实现方式有什么区别吗?
Yoon_EunHae 2008-05-26
  • 打赏
  • 举报
回复
动态规划 .!
tailzhou 2008-05-25
  • 打赏
  • 举报
回复
其中 dp[i,j,k],j <=k,
==>
其中 dp[i,j,k],j < k,
tailzhou 2008-05-25
  • 打赏
  • 举报
回复
从起点开始两走法分别走一步,次终点(p[1,2],p[2,1])只有c(2,2)==1种可能的组合;
从起点开始两走法分别走两步,次终点(p[1,3],p[2,2],p[1,3])只有c(3,2)==3种可能的组合;
....
从起点开始两走法分别走i步,次终点有C(N-abs(N-1-i),2)种可能的组合;

因为N<=8,最大的组合数==C(8,2)==28,

将两路径分别走了i步后的次终点按照第一维的大小进行编号,1,2,3,...,C(N-abs(N-1-i),2)
使用dp[2*N-1+1,c(N,2)+1,c(N,2)+1]来保存中间结果;

其中 dp[i,j,k],j<=k,表示从起点,两路径分别走了i步,两路径的次终点的编号分别为j,k的时候的最优解;

对于dp[i+1,j,k],只有4种可能的情况:
1)两路径分别走了i步时,次终点的编号分别为j-1,k-1;
2)两路径分别走了i步时,次终点的编号分别为j-1,k;
3)两路径分别走了i步时,次终点的编号分别为j,k-1,;
4)两路径分别走了i步时,次终点的编号分别为j,k;

对于不同的边界,上述的4种中有些不合法;






tailzhou 2008-05-25
  • 打赏
  • 举报
回复
可以证明: 存在两次走法,该两次走法无相交点(起点与终点除外),且该两条路径的和是最优解之一;

假设走法f1+f2是一个最优解法,两路径相交与点p[i,j],之后从点p[i',j']分开;
不妨假设f1从点p[i-1,j]走向p[i,j],f2从点p[i,j-1]走向p[i,j],

1)若p[i'j']是终点;
那么f1该从点p[i-1,j]一直向右到p[i-1,j'+1],然后一直向下到p[i',j'],这样两路径不再相交,且之前经过的所有点仍旧都有经过,新的走法不会比之前的走法的差,即新的走法也是最优的解法;

2)若f1走向点p[i',j'+1],f2走向点p[i'+1,j']
那么f1该从点p[i-1,j]一直向右到p[i-1,j'+1],然后一直向下到p[i',j'+1],这样两路径不再相交,且之前经过的所有点仍旧都有经过,新的走法不会比之前的走法的差,即新的走法也是最优的解法;

3)若f1走向点p[i'+1,j'],f2走向点p[i',j'+1]
注意到在点p[i',j']交换f1,f2走法,并不改变解的大小,这样就跟2)是同一情形;







 
huangyongcheng 2008-05-25
  • 打赏
  • 举报
回复
动态规划,王晓东《算法设计与实验题解》
void dyna()
{
int x1,y1,x2,y2,s,v;
for(int i=0; i<=n; i++)
for(int j=0; j<=n; j++)
for(int k=0; k<=n; k++)
for(int l=0; l<=n; l++)
h[i][j][k][l]=0;
h[1][1][1][1] = g[1][1];
for(s=2; s<=n+n-1; s++){
for(x1=1; x1<=s-1; x1++)
for(x2=1; x2<=s-1;x2++){
y1=s-x1;y2=s-x2;
v= h[x1][y1][x2][y2];
val(x1+1,y1,x2+1,y2,v);
val(x1+1,y1,x2,y2+1,v);
val(x1,y1+1,x2+1,y2,v);
val(x1,y1+1,x2,y2+1,v);
}
}
}

void val(int x1,int y1,int x2,int y2,int v)
{
if(x1==x2&&y1==y2)
h[x1][y1][x2][y2]=max(h[x1][y1][x2][y2],v+g[x1][y1]);
else
h[x1][y1][x2][y2]=max(h[x1][y1][x2][y2],v+g[x1][y1]+g[x2][y2]);
}
cqqqq 2008-05-25
  • 打赏
  • 举报
回复
解释一下DP,不好意思,我初学,不知道什么叫DP
Yoon_EunHae 2008-05-25
  • 打赏
  • 举报
回复
我要DP的,如果没有dp的实现,分就给你了..~
Yoon_EunHae 2008-05-25
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 tailzhou 的回复:]
将两路径分别走了i步后的次终点按照第一维的大小进行编号,1,2,3,...,C(N-abs(N-1-i),2)
==>
将两路径分别走了i步后的次终点,以第一维的大小作为编号;
如: 次终点p[i,k]的编号为i;
[/Quote]
能给个实现码吗?
谢了
lonenomad 2008-05-25
  • 打赏
  • 举报
回复
依行为编程,二叉树,向下为左子树,向右为右子树,结点值为路径的和,底层叶子结点最大的两个为所求。
tailzhou 2008-05-25
  • 打赏
  • 举报
回复
将两路径分别走了i步后的次终点按照第一维的大小进行编号,1,2,3,...,C(N-abs(N-1-i),2)
==>
将两路径分别走了i步后的次终点,以第一维的大小作为编号;
如: 次终点p[i,k]的编号为i;
cqqqq 2008-05-24
  • 打赏
  • 举报
回复
接分...
linpeitian 2008-05-23
  • 打赏
  • 举报
回复
动态规划做,做一个四维数组,dp。
zhoufuguo8802 2008-05-23
  • 打赏
  • 举报
回复
首先要算出每条和不为零的路径的和。然后再比较大小就行了。应该用二叉树来算吧,楼主应该自己多想想,只有思想对了,做起来就容易些。
jiqing_gao 2008-05-23
  • 打赏
  • 举报
回复
gz
cqqqq 2008-05-23
  • 打赏
  • 举报
回复
[code=C/C++][
/*分析构造一棵树,遍历所有叶子,每个叶子对应一条路,并计算,再将这条路上的点的数据改为0,再遍历新的树的叶子,得到每一条路,
计算两条路之和,
例:A -> 13 -> 6 -> 4 -> B

*/
#include <iostream>
#include <vector>
#include<sstream>
#include <fstream>

using namespace std;

int sum1;
int sum2;
int max_sum;
char out_str[50];
char path1[50];
char path2[50];

//#define DE_BUG_TO_DO 1 //定义调试模式

struct point
{
int x,y;
int data;
vector<point*> v_p;
point* parents;
};


point start={0,0,0};
vector<point> vec1;
void visit2(point & temp);
void load_to_vec()
{
ifstream in_put_s("res//math_data.txt");
int x=0,y=0,data=0;
while(in_put_s>>x>>y>>data)
{
point temp_p={x,y,data};
vec1.push_back(temp_p);
}
}
void add_next(point &temp,vector<point> & vec)
{
for(int i=0;i<vec.size();i++)
{
if(temp.x == vec[i].x && temp.y == vec[i].y)
continue;
if(temp.x <= vec[i].x && temp.y <= vec[i].y)
{
point *p=new point;
*p=vec[i];
temp.v_p.push_back(p);
p->parents=&temp;
add_next(*p,vec);
}
}
}
//遍历查找叶子节点,并计算当前路径上的数据和sum1;
void visit(point & temp)
{
if( temp.v_p.size()==0)
{
point *p;
p=&temp;
vector<point> vec2(vec1);

sprintf(path1,"第一条路径为: ");
sum1=0;
while( p->data!=0)
{
sum1+=p->data;

sprintf(path1,"%s %d ",path1,p->data);
p=p->parents;
for(int i=0;i<vec2.size();i++)
{
if(vec2[i].x==p->x && vec2[i].y==p->y)
{
vec2.erase(vec2.begin()+i);
}
}
}
point start2={0,0,0};
add_next(start2,vec2);//构造第2棵树
visit2(start2);
return;
}
for(int i=0;i<temp.v_p.size();i++)
{
visit(*(temp.v_p[i]));
}
}
void visit2(point & temp)
{
if( temp.v_p.size()==0)
{
point *p;
p=&temp;
sprintf(path2,"第二条路径为: ");
sum2=0;
while( p->data!=0)
{
sum2+=p->data;
sprintf(path2,"%s %d ",path2,p->data);
p=p->parents;
}

#ifdef DE_BUG_TO_DO

sprintf(out_str,"%s\n%s",path1,path2);
cout<<out_str<<endl;
system("pause");
system("cls");
#else
if( max_sum<sum1+sum2)
{
max_sum=sum1+sum2;

sprintf(out_str,"%s\n%s",path1,path2);
}
#endif
return;
}
for(int i=0;i<temp.v_p.size();i++)
{
visit2(*(temp.v_p[i]));
}
}

void main()
{
load_to_vec();//导入数据
add_next(start,vec1);//构造一棵顶点为start的树
visit(start);//遍历
cout<<out_str<<endl;
cout<<"和为"<<max_sum<<endl;
}
/code]
结构不大严禁,只写出来了 .
ken547315 2008-05-23
  • 打赏
  • 举报
回复
看看 不懂
cqqqq 2008-05-22
  • 打赏
  • 举报
回复
已经算到一条路径的和了,明天给上完整的代码:


/*分析构造一棵树
A
(13) (6) (7) (14) (21) (4) (15) (14)
(6) (7) (4) (14) (15) |(5)|(5)|

*/
#include <iostream>
#include <vector>
#include<sstream>
#include <fstream>

using namespace std;

int sum1;
int sum2;
int max_sum;

struct point
{
int x,y;
int data;
vector<point*> v_p;
point* parents;
};

point start={0,0,0};
vector<point> vec;

void load_to_vec()
{
ifstream in_put_s("res//math_data.txt");
int x=0,y=0,data=0;
while(in_put_s>>x>>y>>data)
{
point temp_p={x,y,data};
vec.push_back(temp_p);
}
}
void add_next(point &temp)
{
for(int i=0;i<vec.size();i++)
{
if(temp.x == vec[i].x && temp.y == vec[i].y)
continue;
if(temp.x <= vec[i].x && temp.y <= vec[i].y)
{
point *p=new point;
*p=vec[i];
temp.v_p.push_back(p);
p->parents=&temp;
add_next(*p);
}
}
}
//遍历查找叶子节点,并计算当前路径上的数据和sum1;
void visit(point & temp)
{
if(temp.v_p.size()==0)
{
point *p;
p=&temp;
sum1=p->data;
while(p->data!=0)
{
p=p->parents;
sum1+=p->data;
}
if(max_sum<sum1)max_sum=sum1;
sum1=0;
return;
}
for(int i=0;i<temp.v_p.size();i++)
{
visit(*(temp.v_p[i]));
}
}

void main()
{
load_to_vec();//导入数据
add_next(start);//构造一棵顶点为start的树
visit(start);//遍历

cout<<max_sum<<endl;
}
9527他大爷 2008-05-22
  • 打赏
  • 举报
回复
我也来mark
加载更多回复(10)

69,382

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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