【DFS】【邻接表】售货员的难题

Description

某乡有 n n n个村庄 ( 1 < n < 40 ) ( 1 < n <40 ) 1n40,有一个售货员,他要到各个村庄去售货,各村庄之间的路程 s ( 0 < s < 1000 ) s(0<s<1000) s(0s1000) 是已知的,且 A A A 村与 B B B 村与 B B B 村与 A A A 村的路大多不同,为了提高效率,他从商店出发到每个村庄一次,然后返回商店所在的村,假设商店所在的村庄为 1 1 1 ,他不知道选择什么样的路才能使所走的路程最短,请你帮助他选择一条路径。

Input

村庄数 n n n 和各村之间的路程(均是整数)

Output

最短路程

Sample Input

3 // 村庄数量
0 2 1 // 村庄 1 到各村的路程
1 0 2
2 1 0

Sample Output

3


解题思路

企图多用一个剪枝,然后把自己剪死了。。。:)

暴力深搜从 1 1 1走回 1 1 1的情况,记录有没有遍历过所有点。

因为每个村庄只走一次,so往回走的时候,直接利用邻接矩阵 a [ r o o t , 1 ] a[root,1] a[root,1]这条路。
但是,我用邻接表,企图利用在,这一题里每条链第一个点必定是 1 1 1的特性,找到 a [ r o o t , 1 ] a[root,1] a[root,1]这条路,发现我wa了。。。:)

假设剩下的点之间通过的路全是1,这种最小情况下,目前求的答案还是大于已求出答案,就可以剪掉。
很好,这个剪枝我没错(欢呼雀跃!!!)


#include<iostream>
#include<cstdio>
using namespace std;
struct DT{
	int to,s,next;
}a[2000];
int head[50],n,v[50],num,Gun=10000;
int demo(int sum,int x){//上述的第一个剪枝,不知为何就是错了
	int i;
	for(i=head[x];a[i].next;i=a[i].next);
	return (sum+a[i].s);
}
void DFS(int dep,int x,int sum){
	if(dep>n){
		Gun=min(Gun,sum);
		return; 
	}
	/*上面我原本打的是
	  if(dep==n){
		Gun=min(Gun,demo(sum,x));
		return; 
	  }
	*/
	if(v[1]==1)return;//不加上就wa了
	if(sum+(n-dep+1)>Gun)return;//上述的第二个剪枝
	for(int i=head[x];i;i=a[i].next){
	    if(!v[a[i].to]){
	    	v[a[i].to]=1;//v标记走没走过
	    	DFS(dep+1,a[i].to,sum+a[i].s);
	    	v[a[i].to]=0;
	    }
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	    for(int j=1;j<=n;j++){
	    	int x;
	    	scanf("%d",&x);
	    	if(x){
	    		a[++num].s=x,a[num].to=j,a[num].next=head[i],head[i]=num;//建邻接表
	        	Gun+=a[num].s;//这个Gun是最终答案,至于为什么要加这些乱七八糟的,是因为我忘记无限大怎么打了。。。
	    	}
	    } 
    DFS(1,1,0);
    printf("%d",Gun);
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值