您的位置:首页 > 其它

【状压DP】售货员的难题

2013-03-03 16:23 183 查看
售货员的难题

源程序名            salesman.???(pas, c, cpp)

可执行文件名        salesman.exe

输入文件名          salesman.in

输出文件名          salesman.out

【问题描述】

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

【输入】

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

【输出】

    最短的路程。

【样例】

    salesman.in                             salesman.out

    3       {村庄数}                        3

    0 2 l       {村庄1到各村的路程}

    1 0 2    {村庄2到各村的路程}

    2 1 0    {村庄3到各村的路程}

本来是搜索练习题,看一个学长把它做成了状压DP,于是我也来试试

用 f [ i ] [ S ] 表示当前到达 i 号点,状态为 S 的最短路,最终我们只需在所有的 f [ i ] [ all ] + map [ i ] [ 1 ] 中找一个最大值即可,all为全为1的01序列

用0表示没走过,1表示走过

那么比如状态S=111,就可以从1号点110,或2号点101,或3号点011走来,这样转移方程就出来了

f [ i ] [ S ] = m i n ( f [ i ] [ S ] , f [ j ] [ S & ( ~ ( 1 < < i ) ) ] ) ; 

做了几道状压DP后再来做这一题,感觉容易多了~

这一题搜索有几组3秒都跑不过,但是DP秒过!

C++ AC Code

#include<cstdio>
#include<algorithm>
using namespace std;

int n,map[20][20];
int f[20][1<<15];

int main()
{
freopen("salesman.in","r",stdin);
freopen("salesman.out","w",stdout);
scanf("%d",&n);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%d",&map[i][j]);
int all=(1<<n)-1;
memset(f,0x3f,sizeof(f));
f[0][0]=0;
for(int i=0;i<n;i++) f[i][1<<i]=map[0][i];
for(int S=0;S<=all;S++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(map[j][i]>0 && (S&(1<<i))!=0)
f[i][S]=min(f[i][S],f[j][S&(~(1<<i))]+map[j][i]);
int res=0x3f3f3f3f;
for(int i=0;i<n;i++) res=min(res,f[i][all]+map[i][0]);
printf("%d\n",res);
return 0;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: