Description
某乡有 n n n个村庄 ( 1 < n < 40 ) ( 1 < n <40 ) (1<n<40),有一个售货员,他要到各个村庄去售货,各村庄之间的路程 s ( 0 < s < 1000 ) s(0<s<1000) s(0<s<1000) 是已知的,且 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);
}