dp[i][i+1]=r[i][i+1];
for(k=3;k<=n;k++)
for(i=1;i<=n-k+1;i++)
{
dp[i][i+k-1]=r[i][i+k-1];
for(j=i+1;j<=i+k-2;j++)
if(dp[i][i+k-1]>dp[i][j]+dp[j][i+k-1])
dp[i][i+k-1]=dp[i][j]+dp[j][i+k-1];
}
while(scanf("%d%d",&i,&j)!
=EOF)
printf("%d\n",dp[i][j]);
return0;
}
运行截图:
实验心得:
本实验运用动态规划方法,由原先构造好的最优解结构编程实现,减小计算量。
贪心算法
⑤问题描述:
利用优先队列及并查集这两个抽象数据类型实现Kruskal算法。
解决方法:
首先将n个顶点看成n个孤立的连通分支,利用优先队列将所有边按权从小到大排列。
然后从第一条边开始,依边权递增的顺序查看每一条边,若该边的两个顶点分属于不同分支,则用边将其连起来,否则看下一条。
用到集合的查找与合并,即并查集数据类型。
代码实现:
#include
#defineMAX_TREE_SIZE100
typedefstructPTNode{//树的双亲表示
intdata;
intparent;
}PTNode;
typedefstruct{
PTNodenodes[MAX_TREE_SIZE];
intn;
}PTree;
typedefPTreeMFSet;//并查集
intinit_mfset(MFSetS){
}
intfind_mfset(MFSetS,inti){
if(i<1||i>S.n)return-1;
intj;
for(j=i;S.nodes[j].parent>0;j=S.nodes[j].parent);
returnj;
}
intmerge_mfset(MFSet&S,inti,intj){
if(i<1||i>S.n||j<1||j>S.n)
return-1;
if(S.nodes[i].parent>S.nodes[j].parent){
S.nodes[j].parent+=S.nodes[i].parent;
S.nodes[i].parent=j;
}
else{
S.nodes[i].parent+=S.nodes[j].parent;
S.nodes[j].parent=i;
}
return1;
}//"mfset.h"
#include
#include"mfset.h"
#include
usingnamespacestd;
structbian
{
doubleweight;
intu,v;
friendbooloperator<(biann1,biann2)
{
returnn1.weight>n2.weight;
}
}edge[100];
biant[100];
intn,e,k;
voidkruskal()
{
priority_queueQ;
for(inti=0;iQ.push(edge[i]);
MFSetS;
S.n=n;
for(inti=1;i<=n;i++)
S.nodes[i].parent=0;
k=0;
while(!
Q.empty()&&k{
bianx=Q.top();
Q.pop();
inta=find_mfset(S,x.u);
intb=find_mfset(S,x.v);
if(a!
=b)
{
t[k++]=x;
merge_mfset(S,a,b);
}
}
}
intmain()
{
scanf("%d%d",&n,&e);
for(inti=0;iscanf("%d%d%lf",&edge[i].u,&edge[i].v,&edge[i].weight);
kruskal();
for(inti=0;iprintf("%d->%d%.3lf\n",t[i].u,t[i].v,t[i].weight);
}
运行截图:
实验心得:
本实验为使代码简洁将并查集代码写到了"mfset.h"作为头文件使用,利用优先队列简单地实现了排序。
用贪心的方法实现了Kruskal算法最小生成树。
回溯法
⑥问题描述:
试设计一个解子集和问题的递归回溯法。
注意对于子集和问题,一旦找到和为c的子集,算法即可终止。
算法中不必记录当前最优解,也不必用数组x记录当前路径。
问题的解可在找到和为c的子集后重新构造。
解决方法:
用子集树递归回溯的方法,1为取,0为不取,一个叶子一个叶子找,找到一组符合元素和为c便停止。
代码实现:
#include
ints,a[1000],n,c;
intback(inti)
{
if(i==n)
{
if(s==c)return1;
elsereturn0;
}
if(s+a[i]<=c)
{
s=s+a[i];
if(back(i+1))return1;
s=s-a[i];
}
if(back(i+1))return1;
return0;
}
intmain()
{
inti;
scanf("%d",&n);
for(i=0;iscanf("%d",&a[i]);
scanf("%d",&c);
s=0;
if(back(0))printf("有子集和为%d的子集。
\n",c);
elseprintf("无子集和为%d的子集。
\n",c);
}
运行截图:
实验心得:
本实验运用回溯法实现,约束条件是子集和为C,一旦找到即可终止,过程中也不需要作记录,因此只要按照条件搜索到就行。