⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tsp.cpp

📁 旅行商问题: 某售货员要到若干城市去推销商品
💻 CPP
字号:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

typedef struct node{
	int x;
	int *ptr;
	struct node *next;
}Node;

__int64 *CN = NULL;

int **CreatIntArray_2(int **Head,int m,int n)
{
    int i,j;
    int *p=NULL;

    if( !(m > 0 && n > 0) ){                              //判断维度是否正确
		printf("错误的数组维度\n");
		return NULL;
	}
    if( !(p = (int *)malloc(sizeof(int) * m * n))){   //申请总体空间
		printf("Malloc error\n");
		return NULL;
	}
    if( !(Head = (int **)malloc(sizeof(int *)*m))){   //申请二级指针空间
		printf("Malloc error\n");
		return NULL;
	}
    for(i = 0;i < m;i++)                
        Head[i]=p + n * i;
    for(i = 0;i < m;i++)                  
        for(j = 0;j < n;j++)
            Head[i][j] = 0;
    return Head;
} 

__int64 C(int n,int k)   //求组合数C(n,k)
{
	int i;
	__int64 up = 1,down = 1;
	
	for(i = n - k + 1; i <= n;i++)
		up *= i;
	for(i = 2; i <= k; i++)
		down *= i;
	return up/down;
}

void FillCN(int n)
{
	int i;
	CN[0] = 1;
	for(i = 1; i <= n; i++){
		if(i > n/2)
			CN[i] = CN[n - i];
		else
			CN[i] = C(n,i);
		//printf("%ld ",CN[i]);
	}
}
int NumOf(long a,int n) //求长整型数a的二进制表示中1的个数,n为最多的1的个数
{
	int i,num = 0;
	for(i = 0; i < n;i++)
		if((a & (1<<i)) != 0) //注意(a & (1<<i))外层的括号不能少
			num++;
	return num;
}
int GetDiff(long a,long b,int n)  //求回溯路径,找出那位二进制位不同
{
	int i;
	for(i = 1; i <= n;i++){
		if(((a & 1<<(i - 1)) ^ (b & 1<<(i - 1))) != 0)
			return i;
	}
}
void ReArry(long L,int n,int **a,int **b)  //根据数L返回两个数组,数组a包含1的位置,数组b包含0的位置,n为最多的1的个数
{
	int i,j,k,l;

	j = NumOf(L,n);
	if( !(*a = (int *)malloc(sizeof(int)*(j+1)))){   //申请二级指针空间
		printf("Malloc error\n");
		return ;
	}
	(*a)[0] = j;  //a[0]放置1的个数
	if( !(*b = (int *)malloc(sizeof(int)*(n-j+1)))){   //申请二级指针空间
		printf("Malloc error\n");
		return ;
	}
	(*b)[0] = n - j;  //b[0]放置0的个数
	k = l = 1;
	for(i = 0; i < n;i++)  //在数组a和b中放置1和0信息
		if((L & (1<<i)) != 0) //注意(a & (1<<i))外层的括号不能少
			(*a)[k++] = i + 1;
		else
			(*b)[l++] = i + 1;
	
}

int main(void)
{
	int i,k,f,q,g,temp,m,n;  //m为输入的顶点个数,n为m-1,表示除顶点外的顶点个数
	int *a = NULL,*b = NULL;//用于存放1和0的位置信息
	long l,nl;//l为长整型循环变量,nl为集合的个数
	FILE *fp;
	int **G = NULL;//存放顶点信息
	Node *N = NULL;//集合数组
	Node **P = NULL,**Q = NULL;  //指针数组,用于存放指向Node类型的指针
	__int64 j,h;
	clock_t start,end; //测试程序运行时间

	start = clock();
	if(!(fp = fopen("TSP.txt","r"))){
		printf("Open file error\n");
		return -1;
	}

	fscanf(fp,"%d",&m);  //读取顶点个数

	n = m - 1;  //n为除顶点外的点的个数
	
	if(!(G = CreatIntArray_2(G,m,m))){
		printf("Malloc G error!\n");
		return -1;
	}

	for(i = 0; i < m; i++)
		for(j = 0; j < m; j++)
			fscanf(fp,"%d",&G[i][j]);
/*****************************	
   //打印顶点信息
	for(i = 0; i < m; i++){
		for(j = 0; j < m; j++)
			printf("%d ",G[i][j]);
		printf("\n");
	}
******************************/
	fclose(fp);

//	printf("%d",NumOf((long)15,4));
//	printf("%d",C(20,10));
//	printf("%d",GetDiff(41,25,n));
	nl = (1<<n);
	if( !(CN = (__int64 *)malloc(sizeof(__int64)*(n+1)))){   //给集合数组申请空间
		printf("Malloc error\n");
		return NULL;
	}
	FillCN(n);
/*	for(i = 1; i <= n;i++)
		printf("%ld ",CN[i]);*/
	if( !(N = (Node *)malloc(sizeof(Node)*nl))){   //给集合数组申请空间
		printf("Malloc error\n");
		return NULL;
	}
	if( !(P = (Node **)malloc(sizeof(Node *)*(n + 1)))){   //给集合数组申请空间
		printf("Malloc error\n");
		return NULL;
	}
	if( !(Q = (Node **)malloc(sizeof(Node *)*(n + 1)))){   //给集合数组申请空间
		printf("Malloc error\n");
		return NULL;
	}
	for(i = 0; i <= n;i++)
		P[i] = Q[i] = NULL;

	for(l = 0; l < nl; l++){
		N[l].x = l;
		N[l].next = NULL;
		j = NumOf(l,n);
		if(P[j] == NULL)
			P[j] = Q[j] = &N[l];
		else{
			P[j]->next = &N[l];
			P[j] = &N[l];
		}
	}
/**********************************************************
   //按照1的个数,逐行打印集合信息
	for(i = 1; i <= n;i++)
		P[i] = Q[i];
	for(l = 1; l <= n; l++){
		nl = C(n,l);
		for(j = 1; j <= nl;j++,P[l] = P[l]->next)
			printf("%d ",P[l]->x);
		printf("\n");
	}
***********************************************************/
	//初始化含1的个数为一的集合
	for(i = 1; i <= n;i++)  //回调P指针
		P[i] = Q[i];

	for(i = 1; i <= n; i++,P[1] = P[1]->next){//对n和只含一个的集合操作
		if( !(P[1]->ptr = (int *)malloc(sizeof(int)*(n+1)))){   //给集合数组申请空间
			printf("Malloc error\n");
			return NULL;
		}
		ReArry(P[1]->x,n,&a,&b);
		for(j = 1; j <= b[0]; j++){
			(P[1]->ptr)[b[j]] = G[0][a[1]] + G[a[1]][b[j]];
	//		printf("%d ",(P[1]->ptr)[b[j]]);
		}
		free(a);
		free(b);
	//	printf("\n");
	}
	for(i = 2; i <= n - 1;i++){  //对所有含1的个数为i的集合操作
		h = CN[i];       //一共有h各这样的集合
		for(j = 1,P[i] = Q[i]; j <= h;j++,P[i] = P[i]->next){  //对每个这样的集合操作
			ReArry(P[i]->x,n,&a,&b);
			if( !(P[i]->ptr = (int *)malloc(sizeof(int)*(n+1)))){   //给集合数组申请空间
				printf("Malloc error\n");
				return NULL;
			}
			for(k = 1; k <= b[0]; k++){ //对该集合拉出来的数组进行填写,填写位置是0的顶点
				temp = 35766;
				for(f = 1; f <= a[0]; f++){  //根据上一次的填表填写这次的数值
					g = (P[i]->x) & ~(1<<(a[f] - 1));  //取得上次的位置
					q = (N[g].ptr)[a[f]] + G[a[f]][b[k]];
					if(q < temp){
						temp = q;
						(P[i]->ptr)[0] = g;
					}
				}
				(P[i]->ptr)[b[k]] = temp;
			}
			free(a);
			free(b);
		}
	}
	temp = 35766;
	P[n] = Q[n];   //最后一次填表,得出结果
	if( !(P[n]->ptr = (int *)malloc(sizeof(int)*(2)))){   //给集合数组申请空间
		printf("Malloc error\n");
		return NULL;
	}
	for(i = 1; i <= n; i++){
		g = (P[n]->x) & ~(1<<(i - 1));  //取得上次的位置
		q = (N[g].ptr)[i] + G[i][0];
		if(q < temp){
			temp = q;
			(P[n]->ptr)[0] = g;
		}
	}
	(P[n]->ptr)[1] = temp;
	printf("顶点个数为%d\n最短路径长度为:%d\n",m,temp);
/***********************************************************************
	//测试ReArry函数
	ReArry(19,5,&a,&b);
	for(i = 1; i <= a[0];i++)
		printf("%d ",a[i]);
	printf("\n");
	for(i = 1; i <= b[0];i++)
		printf("%d ",b[i]);
************************************************************************/
	end = clock();
	l = nl - 1;
	printf("%d->",1);
	for(i = 1; i < n;i++){ //每次输出一个顶点
		printf("%d->",GetDiff(l,(N[l].ptr)[0],n)+1);
		l = (N[l].ptr)[0];
	}
	for(i = 1;i <= n;i++){
		if((l & (1<<(i - 1))) != 0){
			printf("%d",i+1);
			break;
		}
	}
	printf("->%d",1);
	
	printf("\n程序运行%lf秒\n",(double)(end - start) /  CLK_TCK);
/*删除空间,图形显示*/
	return 1;
			
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -