• 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哟;

       

  • 相关阅读:
    VS2010工具箱中的控件突然全部都不见了的问题解决
    wpf用户控件 弹出窗口因主窗体最小化而消失的问题
    未解析成员Csla.Security.UnauthenticatedPrincipal,Csla,异常
    服务器被入侵,管理员账号密码被改,策略以及维护
    telerik for asp 的引用问题
    decimal简单问题
    vs2008的网站升级为vs2010遇到的问题
    VS2010设置默认以管理员权限打开
    lhgdialog基础
    SQL Server 2005镜像删除备忘录
  • 原文地址:https://www.cnblogs.com/nietzsche-oier/p/6296862.html
Copyright © 2020-2023  润新知