• 售货员的难题(codevs 2596)


    题目描述 Description

    某乡有n个村庄(1<n<=15),有一个售货员,他要到各个村庄去售货,各村庄之间的路程s(0<s<1000)是已知的,且A村到B村与B村到A村的路大多不同。为了提高效率,他从商店出发到每个村庄一次,然后返回商店所在的村,假设商店所在的村庄为1,他不知道选择什么样的路线才能使所走的路程最短。请你帮他选择一条最短的路。

    输入描述 Input Description

    村庄数n和各村之间的路程(均是整数)

    输出描述 Output Description

    最短的路程

    样例输入 Sample Input

    3

    0 2 1

    1 0 2

    2 1 0

    样例输出 Sample Output

    3

    数据范围及提示 Data Size & Hint

    本题可用最短路思想、搜索来解决,但是可能无法通过一组极限数据(且效率较低)。建议按树状DP考虑!

    /*
      不会什么树形DP,我做的是spfa(其实floyed就可以)+深搜+剪枝
      首先将边反向,spfa处理所有点到1的距离,以备剪枝使用
      然后深搜得到答案
      剪枝:利用spfa得到的距离,当当前的dis+(n-t)*minn+f[x]>ans时,剪枝
        (minn是矩阵中的最短距离,n-t是还有几步可以遍历完所有的村庄) 
    */
    #include<cstring>
    #include<cstdio>
    #include<iostream>
    #include<queue>
    #define M 20
    #define INF 3000000
    using namespace std;
    int map[M][M],f[M],n,ans=INF,min1=INF;
    int a2[M][M];
    bool vis[M];
    queue<int> q;
    int read()
    {
        char c=getchar();int num=0,flag=1;
        while(c<'0'||c>'9'){if(c=='-')flag=-1;c=getchar();}
        while(c>='0'&&c<='9'){num=num*10+c-'0';c=getchar();}
        return num*flag;
    }
    void dfs(int x,int t,int dis)
    {
        if(dis>ans)return;
        if(dis+(n-t)*min1+f[x]>ans)return;
        if(t==n)
        {
            ans=min(ans,dis+map[x][1]);
            return;
        }
        for(int i=1;i<=n;i++)
          if(!vis[i])
          {
              vis[i]=true;
              dfs(i,t+1,dis+map[x][i]);
              vis[i]=false;
          }
    }
    void spfa()
    {
        q.push(1);
        vis[1]=1;
        f[1]=0;
        while(!q.empty())
        {
            int x=q.front();
            q.pop();
            vis[x]=0;
            for(int i=1;i<=n;i++)
              if(a2[x][i]&&f[x]+a2[x][i]<f[i])
              {
                  f[i]=f[x]+a2[x][i];
                  if(!vis[i])
                  {
                      vis[i]=1;
                      q.push(i);
                  }
              }
        }
    }
    int main()
    {
        memset(f,0x3f3f3f3f,sizeof(f));
        n=read();
        for(int i=1;i<=n;i++)
          for(int j=1;j<=n;j++)
          {
              map[i][j]=read();
              a2[j][i]=map[i][j];
              min1=min(min1,map[i][j]);
          }
        spfa();
        memset(vis,0,sizeof(vis));
        vis[1]=1;
        dfs(1,1,0);
        printf("%d",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    (转载)C#控件缩写规范
    ToString()格式和用法大全,C#实现保留两位小数的方法
    C#数字前面如何补0
    (转载)C#语言开发规范
    (转载)C#:Enum、Int和String的互相转换,枚举转换
    [踩坑系列]URLEncode 中对 空格的编码有 “+”和“%20”两种
    [IDEA]IDEA设置注释模板
    [Mybatis]Mybatis 常用标签及功能整理
    [设计模式]静态代理
    记一次java电话面试
  • 原文地址:https://www.cnblogs.com/harden/p/5742805.html
Copyright © 2020-2023  润新知