货员的难题
这题我在洛谷得了80分,此结果仅供参考
题目描述
某乡有n个村庄(1<n≤40),有一个售货员,他要到各个村庄去售货,各村庄之间的路程s(0<s<1000)是已知的,且A村到B村与B村到A村的路大多不同。为了提高效率,他从商店出发到每个村庄一次,然后返回商店所在的村,假设商店所在的村庄为1,他不知道选择什么样的路线才能使所走的路程最短。请你帮他选择一条最短的路。
输入格式
村庄数n和各村之间的路程(均是整数)。
输出格式
最短的路程。
输入输出样例
输入
3
0 2 1
1 0 2
2 1 0
输出
3
分析
这题我们可以用深搜(DFS)(邻接表)来做
依题意我们可以知道,这题就是个搜索
但是,有一个地方十分特殊
就是其他村庄都走过了,下一个点是起点
这里是不能回溯的
所以要
if(c[f[i].to]==0)//下一个点你能不能走
{
c[f[i].to]=1;
dfs(f[i].to,sum+f[i].s,ans+1);
c[f[i].to]=0;//回溯
}
if(f[i].to==1&&ans==n-1)dfs(f[i].to,sum+f[i].s,ans+1);//下一个点是起点,且其他村庄已走过
分开来
代码
#include<iostream>
using namespace std;
int tot,n,a,c[45],head[2005];
long long m;
struct stu//结构体
{
int to,next,s;
}f[2005];
void add(int x,int y,int s)//邻接表
{
tot++;
f[tot].to=y;//子节点
f[tot].next=head[x];//下一个
f[tot].s=s;//当前值
head[x]=tot;//方便下一个找自己
}
void dfs(int now,long long sum,int ans)//有三个,now是当前村庄,sum是当前路程,ans是通过村庄个数
{
if(ans>=n){if(sum<m)m=sum;return;}//如果通过n个村庄,就说明回到了起点
if(sum>=m)return; //剪枝,超过了最小值就跳过
for(int i=head[now];i;i=f[i].next)
if(f[i].s+sum<m)//要小于最小值
{
if(c[f[i].to]==0)//下一个点你能不能走
{
c[f[i].to]=1;
dfs(f[i].to,sum+f[i].s,ans+1);
c[f[i].to]=0;//回溯
}
if(f[i].to==1&&ans==n-1)dfs(f[i].to,sum+f[i].s,ans+1);//下一个点是起点,且其他村庄已走过
}
return;
}
int main()
{
m=2147483647;//设很大,找最小
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
cin>>a;
if(a!=0)//自己不能走自己
add(i,j,a);
}
c[1]=1;//起点为一
dfs(1,0,0); //初值
cout<<m;
}