‘壹’ 近似算法的顶点覆盖问题的近似算法
问题描述:无向图G=(V,E)的顶点覆盖是它的顶点集V的一个子集V’,使得若(u,v)是G的一条边,则v∈V’或u∈V’。顶点覆盖V’的大小是它所包含的顶点个数|V’|。
VertexSet approxVertexCover ( Graph g )
{ cset=NULL;
e1=g.e;
while (e1 !=NULL) {
从e1中任取一条边(u,v);
cset=cset∪{u,v};
从e1中删去与u和v相关联的所有边;
}
return c
}
Cset用来存储顶点覆盖中的各顶点。初始为空,不断从边集e1中选取一边(u,v),将边的端点加入cset中,并将e1中已被u和v覆盖的边删去,直至cset已覆盖所有边。即e1为空。
图(a)~(e)说明了算法的运行过程及结果。(e)表示算法产生的近似最优顶点覆盖cset,它由顶点b,c,d,e,f,g所组成。(f)是图G的一个最小顶点覆盖,它只含有3个顶点:b,d和e。
‘贰’ 马的遍历 马在8*8的棋盘上能遍历吗
此题涉及到贪婪法算法,它是一种不追求最优解,只希望得到较为满意解的方法。贪婪法一般可以快速得到满意的解,因为它省去了为找最优解要穷尽所有可能而必须耗费的大量时间。贪婪法常以当前情况为基础作最优选择,而不考虑各种可能的整体情况,所以贪婪法不要回溯。
马在某个方格,可以在一步内到达的不同位置最多有8个,如用二维数组board[ ][ ]表示棋盘,其元素记录马经过该位置时的步骤号。另对马的8种可能走法(称为着法)设定一个顺序,如当前位置在棋盘的(i,j)方格,下一个可能的位置依次为(i+2,j+1)、(i+1,j+2)、(i-1,j+2)、(i-2,j+1)、(i-2,j-1)、(i-1,j-2)、(i+1,j-2)、(i+2,j-1),实际可以走的位置尽限于还未走过的和不越出边界的那些位置。为便于程序的同意处理,可以引入两个数组,分别存储各种可能走法对当前位置的纵横增量。
4 3
5 2
马
6 1
7 0
对于本题,一般可以采用回溯法,这里采用Warnsdoff策略求解,这也是一种贪婪法,其选择下一出口的贪婪标准是在那些允许走的位置中,选择出口最少的那个位置。如马的当前位置(i,j)只有三个出口,他们是位置(i+2,j+1)、(i-2,j+1)和(i-1,j-2),如分别走到这些位置,这三个位置又分别会有不同的出口,假定这三个位置的出口个数分别为4、2、3,则程序就选择让马走向(i-2,j+1)位置。
由于程序采用的是一种贪婪法,整个找解过程是一直向前,没有回溯,所以能非常快地找到解。但是,对于某些开始位置,实际上有解,而该算法不能找到解。对于找不到解的情况,程序只要改变8种可能出口的选择顺序,就能找到解。改变出口选择顺序,就是改变有相同 出口时的选择标准。以下程序考虑到这种情况,引入变量start,用于控制8种可能着法的选择顺序。开始时为0,当不能找到解时,就让start增1,重新找解。细节以下程序。
【程序】
# include <stdio.h>
int delta_i[ ]={2,1,-1,-2,-2,-1,1,2};
int delta_j[ ]={1,2,2,1,-1,-2,-2,-1};
int board[8][8];
int exitn(int i,int j,int s,int a[ ])
{ int i1,j1,k,count;
for (count=k=0;k<8;k++)
{ i1=i+delta_i[(s+k)%8];
j1=i+delta_j[(s+k)%8];
if (i1>=0&&i1<8&&j1>=0&&j1<8&&board[I1][j1]==0)
a[count++]=(s+k)%8;
}
return count;
}
int next(int i,int j,int s)
{ int m,k,mm,min,a[8],b[8],temp;
m=exitn(i,j,s,a);
if (m==0) return –1;
for (min=9,k=0;k<m;k++)
{ temp=exitn(I+delta_i[a[k]],j+delta_j[a[k]],s,b);
if (temp<min)
{ min=temp;
kk=a[k];
}
}
return kk;
}
void main()
{ int sx,sy,i,j,step,no,start;
for (sx=0;sx<8;sx++)
for (sy=0;sy<8;sy++)
{ start=0;
do {
for (i=0;i<8;i++)
for (j=0;j<8;j++)
board[j]=0;
board[sx][sy]=1;
I=sx; j=sy;
For (step=2;step<64;step++)
{ if ((no=next(i,j,start))==-1) break;
I+=delta_i[no];
j+=delta_j[no];
board[j]=step;
}
if (step>64) break;
start++;
} while(step<=64)
for (i=0;i<8;i++)
{ for (j=0;j<8;j++)
printf(“%4d”,board[j]);
printf(“\n\n”);
}
scanf(“%*c”);
}
}
‘叁’ 马的走法C语言算法
#include<stdio.h>
/*
* 求(x1,y1)向右走到(y1,y2)可行的走法总数
*/
int getWays(int x1, int y1, int x2, int y2)
{
if(y1 > y2) //在目标右边
return 0;
else if(y1 == y2 && x1 != x2) //在目标一条垂直线上,但不是同一点
return 0;
else if(y1 == y2 && x1 == x2) //跟目标是同一点
return 1;
else{ //分治,求四种走法的总和
int result =0;
if(x1 > 1) //可以上1
result += getWays(x1 - 1, y1 + 2, x2, y2);
if(x1 > 2) //可以上2
result += getWays(x1 - 2, y1 + 1, x2, y2);
if(x1 < 5) //可以下1
result += getWays(x1 + 1, y1 + 2, x2, y2);
if(x1 < 4) //可以下2
result += getWays(x1 + 2, y1 + 1, x2, y2);
return result;
}
}
void main(void)
{
int x,y; //目标坐标
printf("请输入目标坐标:\n");
scanf("%d%d", &x, &y);
printf("总的不同走法:%d\n",getWays(1, 1, x, y));
}
不明白,再交流...
‘肆’ 在中国象棋棋盘上实现上一课题的任务:在中国象棋棋盘上,如果放置若干个马后,使得整个棋盘后的任意空位
我想是这样的吧。
‘伍’ 数据结构课程设计报告 马的遍历 麻烦了
//图的遍历算法程序
//图的遍历是指按某条搜索路径访问图中每个结点,使得每个结点均被访问一次,而且仅被访问一次。图的遍历有深度遍历算法和广度遍历算法,程序如下:
#include <iostream>
//#include <malloc.h>
#define INFINITY 32767
#define MAX_VEX 20 //最大顶点个数
#define QUEUE_SIZE (MAX_VEX+1) //队列长度
using namespace std;
bool *visited; //访问标志数组
//图的邻接矩阵存储结构
typedef struct{
char *vexs; //顶点向量
int arcs[MAX_VEX][MAX_VEX]; //邻接矩阵
int vexnum,arcnum; //图的当前顶点数和弧数
}Graph;
//队列类
class Queue{
public:
void InitQueue(){
base=(int *)malloc(QUEUE_SIZE*sizeof(int));
front=rear=0;
}
void EnQueue(int e){
base[rear]=e;
rear=(rear+1)%QUEUE_SIZE;
}
void DeQueue(int &e){
e=base[front];
front=(front+1)%QUEUE_SIZE;
}
public:
int *base;
int front;
int rear;
};
//图G中查找元素c的位置
int Locate(Graph G,char c){
for(int i=0;i<G.vexnum;i++)
if(G.vexs[i]==c) return i;
return -1;
}
//创建无向网
void CreateUDN(Graph &G){
int i,j,w,s1,s2;
char a,b,temp;
printf("输入顶点数和弧数:");
scanf("%d%d",&G.vexnum,&G.arcnum);
temp=getchar(); //接收回车
G.vexs=(char *)malloc(G.vexnum*sizeof(char)); //分配顶点数目
printf("输入%d个顶点.\n",G.vexnum);
for(i=0;i<G.vexnum;i++){ //初始化顶点
printf("输入顶点%d:",i);
scanf("%c",&G.vexs[i]);
temp=getchar(); //接收回车
}
for(i=0;i<G.vexnum;i++) //初始化邻接矩阵
for(j=0;j<G.vexnum;j++)
G.arcs[i][j]=INFINITY;
printf("输入%d条弧.\n",G.arcnum);
for(i=0;i<G.arcnum;i++){ //初始化弧
printf("输入弧%d:",i);
scanf("%c %c %d",&a,&b,&w); //输入一条边依附的顶点和权值
temp=getchar(); //接收回车
s1=Locate(G,a);
s2=Locate(G,b);
G.arcs[s1][s2]=G.arcs[s2][s1]=w;
}
}
//图G中顶点k的第一个邻接顶点
int FirstVex(Graph G,int k){
if(k>=0 && k<G.vexnum){ //k合理
for(int i=0;i<G.vexnum;i++)
if(G.arcs[k][i]!=INFINITY) return i;
}
return -1;
}
//图G中顶点i的第j个邻接顶点的下一个邻接顶点
int NextVex(Graph G,int i,int j){
if(i>=0 && i<G.vexnum && j>=0 && j<G.vexnum){ //i,j合理
for(int k=j+1;k<G.vexnum;k++)
if(G.arcs[i][k]!=INFINITY) return k;
}
return -1;
}
//深度优先遍历
void DFS(Graph G,int k){
int i;
if(k==-1){ //第一次执行DFS时,k为-1
for(i=0;i<G.vexnum;i++)
if(!visited[i]) DFS(G,i); //对尚未访问的顶点调用DFS
}
else{
visited[k]=true;
printf("%c ",G.vexs[k]); //访问第k个顶点
for(i=FirstVex(G,k);i>=0;i=NextVex(G,k,i))
if(!visited[i]) DFS(G,i); //对k的尚未访问的邻接顶点i递归调用DFS
}
}
//广度优先遍历
void BFS(Graph G){
int k;
Queue Q; //辅助队列Q
Q.InitQueue();
for(int i=0;i<G.vexnum;i++)
if(!visited[i]){ //i尚未访问
visited[i]=true;
printf("%c ",G.vexs[i]);
Q.EnQueue(i); //i入列
while(Q.front!=Q.rear){
Q.DeQueue(k); //队头元素出列并置为k
for(int w=FirstVex(G,k);w>=0;w=NextVex(G,k,w))
if(!visited[w]){ //w为k的尚未访问的邻接顶点
visited[w]=true;
printf("%c ",G.vexs[w]);
Q.EnQueue(w);
}
}
}
}
//主函数
void main(){
int i;
Graph G;
CreateUDN(G);
visited=(bool *)malloc(G.vexnum*sizeof(bool));
printf("\n广度优先遍历: ");
for(i=0;i<G.vexnum;i++)
visited[i]=false;
DFS(G,-1);
printf("\n深度优先遍历: ");
for(i=0;i<G.vexnum;i++)
visited[i]=false;
BFS(G);
printf("\n程序结束.\n");
}
输出结果为(红色为键盘输入的数据,权值都置为1):
输入顶点数和弧数:8 9
输入8个顶点.
输入顶点0:a
输入顶点1:b
输入顶点2:c
输入顶点3:d
输入顶点4:e
输入顶点5:f
输入顶点6:g
输入顶点7:h
输入9条弧.
输入弧0:a b 1
输入弧1:b d 1
输入弧2:b e 1
输入弧3:d h 1
输入弧4:e h 1
输入弧5:a c 1
输入弧6:c f 1
输入弧7:c g 1
输入弧8:f g 1
广度优先遍历: a b d h e c f g
深度优先遍历: a b c d e f g h
程序结束.
‘陆’ 最小满覆盖 中国象棋
呵呵
多看棋书会提高象棋水平的