P1171 售货员的难题 喻队状压 DP
Posted 古时候的瘾君子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1171 售货员的难题 喻队状压 DP相关的知识,希望对你有一定的参考价值。
题目描述
某乡有n个村庄(1<n<20),有一个售货员,他要到各个村庄去售货,各村庄之间的路程s(0<s<1000)是已知的,且A村到B村与B村到A村的路大多不同。为了提高效率,他从商店出发到每个村庄一次,然后返回商店所在的村,假设商店所在的村庄为1,他不知道选择什么样的路线才能使所走的路程最短。请你帮他选择一条最短的路。
输入输出格式
输入格式:
村庄数n和各村之间的路程(均是整数)。
输出格式:
最短的路程。
输入输出样例
输入样例#1:
3 0 2 1 1 0 2 2 1 0
输出样例#1:
3
说明
输入解释
3 {村庄数}
0 2 1 {村庄1到各村的路程}
1 0 2 {村庄2到各村的路程}
2 1 0 {村庄3到各村的路程}
差不多是我第一次做状压题,参考了洛谷的题解(明明就是一样的),总的来说差不多理解了状压。
状压的状态转移是由位运算来优化实现的,一般用两个位运算:
get : 用来确定某一位是否走过(define最快)
#define get(a , b) ((a >> b-1) & 1)
replace:用来得到之前的状态(依旧是define)
#define get(a , b) ((a >> b-1) & 1)
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define ll long long #define il inline #define db double #define replace(a , b) (a ^ (1 << b-1)) #define get(a , b) ((a >> b-1) & 1) #define min(a , b) ((a) < (b) ? (a) : (b)) using namespace std; il int gi() { int x=0,y=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘) { if(ch==‘-‘) y=-1; ch=getchar(); } while(ch>=‘0‘&&ch<=‘9‘) { x=x*10+ch-‘0‘; ch=getchar(); } return x*y; } int n,m,f[1<<21][21],r[21][21],ans=2e9,s; int main() { n=gi(); m=(1<<n)-1; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) r[i][j]=gi(); for(int i=1;i<=m;i+=2) for(int j=1;j<=n;j++) f[i][j]=2e9; f[1][1]=0; for(int i=3,k=2,p=4;i<=m;i+=2) { if(i>p) p=p<<1,k++; for(int j=2;j<=k;j++) { if(get(i,j)) { s=replace(i,j); for(int l=1;l<j;l++) f[i][j]=min(f[i][j],f[s][l]+r[l][j]); for(int l=j+1;l<=k;l++) f[i][j]=min(f[i][j],f[s][l]+r[l][j]); } } } for(int i=2;i<=n;i++) ans=min(ans,f[m][i]+r[i][1]); printf("%d\n",ans); return 0; }
以上是关于P1171 售货员的难题 喻队状压 DP的主要内容,如果未能解决你的问题,请参考以下文章