POJ 3311Hie with the Pie

    The Pizazz Pizzeria prides itself in delivering pizzas to its customers as fast as possible. Unfortunately, due to cutbacks, they can afford to hire only one driver to do the deliveries. He will wait for 1 or more (up to 10) orders to be processed before he starts any deliveries. Needless to say, he would like to take the shortest route in delivering these goodies and returning to the pizzeria, even if it means passing the same location(s) or the pizzeria more than once on the way. He has commissioned you to write a program to help him.

大概是给个图,求从0路过所有点再回来的最短路长(当然可以重复)

                      ——by POJ

http://poj.org/problem?id=3311



    我们可以认为我们现在已经有一条路径了,那么这条路径里显然重复地存在所有点,我们从她中间挑出一份n个点,按她们在路径中的位置排列,则在这个序列中相邻的两点在原路径中的间隔点一定是她们之间的最短路。

    所以这条路径可以看做是由n条(因为是N+1个点)最短路构成的。

    所以可以Floyd最短路,剩下的可以写状压,DP出n个点按什么顺序最优:

    f[i][num](i:当前所在的点;num:当前状态,二进制数,0为没走1为走过)

    f[i][num|k]=f[j][num]+a[j][i]( 前提是num&k==0且这样可以更优)

    这个时候不必考虑可以重复的性质——因为重复的唯一作用是作为两点间的中继点使路径更短,但两点间无论以什么为中继点,都不会比她的最短路短,故不必重复。

    因为懒所以直接写了记忆化

    代码如下:

#include<cstdio>
#include<cstring>
using namespace std;
int map[11][11];
long long f[11][4100];
int n;

void work();
void floy();
long long dfs(int ,int );

int main()
{
    int T;
    scanf("%d",&n);
    while(n)
    {
        work();
        scanf("%d",&n);
    }
    return 0;
}

void work()
{
    int i,j,k;
    long long ans=0;
    memset(f,0,sizeof(f));
    for(i=0;i<=n;i++)
        for(j=0;j<=n;j++)
            scanf("%d",&map[i][j]);
    floy();j=2;
    for(i=1;i<=n;i++)
        f[i][j]=map[0][i],j=j<<1;
    ans=dfs(0,j-1);
    printf("%lld
",ans);
    return ;
}
//f[i][j]=f[k..][l..]+map[k..][i];
void floy()
{
    int i,j,k;
    for(k=0;k<=n;k++)
      for(i=0;i<=n;i++)
        for(j=0;j<=n;j++)
          if(map[i][k]&&map[k][j]&&i!=j)
            if(map[i][j]==0||map[i][j]>map[i][k]+map[k][j])
              map[i][j]=map[i][k]+map[k][j];
}

long long dfs(int i,int num)
{
    if(f[i][num])
        return f[i][num];
    int j,k;
    long long l;
    j=1;
    for(k=0;k<=n;k++)
    {
        if(j&num&&k!=i)
        {
            l=dfs(k,num^(1<<i));
            if(f[i][num]>l+map[k][i]||f[i][num]==0)
               f[i][num]=l+map[k][i];
        }
        j=j<<1;
    }
    return f[i][num];
}

祝AC哟;

   

原文地址:https://www.cnblogs.com/nietzsche-oier/p/6296862.html