【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]);
View Code

这里有一个细节,设初始状态为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;
}
View Code

 

posted @ 2017-03-05 13:52  ONION_CYC  阅读(381)  评论(0编辑  收藏  举报