【CODEVS】2800 送外卖
【算法】最短路(floyd)+状态压缩型动态规划
【题解】
经典的TSP问题(货郎担问题):求最小权哈密顿回路(遍历全图点一次且仅一次)。本题稍作改动,先说原TSP问题解法:状压DP。
状态用二进制表示每个点是否走过(状态也包括最后走的点),状态转移关键在于每个点都有且只有另一个点指向它,所以先可以枚举状态k(按顺序枚举时,后面集合的子集已经全部计算完毕),
对于每个状态枚举最后到达的节点i,再枚举i的所有邻边节点j,从恰好缺i且最后节点为j的状态转移过来。
memset(f,0x3f,sizeof(f));//初始化为正无穷 f[1][0]=0;//不算起点 for(int k=1;k<=(1<<n)-1;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if((1<<(i-1))&k)f[i][k]=min(f[i][k],f[j][k-(1<<(i-1))]+mp[j][i]); printf("%d",f[1][(1<<n)-1]);
这里有一个细节,设初始状态为f[1][0]=0(起点为1),即起点的初态不包含自身,那么最后f[1][(1<<n)-1]就是答案。
那么这道题的修改主要是一个城市可以经过多次,那么先跑一遍floyd得出两城市间最短距离后就不必再纠结重复经过的事了。
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=20; int n,mp[maxn][maxn],f[maxn][70010]; int main() { scanf("%d",&n);n++; int x; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { scanf("%d",&x); mp[i][j]=x; } } for(int i=1;i<=n;i++)mp[i][i]=0; for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]); memset(f,0x3f,sizeof(f)); f[1][0]=0; for(int k=1;k<=(1<<n)-1;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if((1<<(i-1))&k)f[i][k]=min(f[i][k],f[j][k-(1<<(i-1))]+mp[j][i]); printf("%d",f[1][(1<<n)-1]); return 0; }