zoukankan      html  css  js  c++  java
  • CODEVS_2800 送外卖 状态压缩+动态规划

    原题链接:http://codevs.cn/problem/2800/

    题目描述 Description

    有一个送外卖的,他手上有n份订单,他要把n份东西,分别送达n个不同的客户的手上。n个不同的客户分别在1~n个编号的城市中。送外卖的从0号城市出发,然后n个城市都要走一次(一个城市可以走多次),最后还要回到0点(他的单位),请问最短时间是多少。现在已知任意两个城市的直接通路的时间。

    输入描述 Input Description

    第一行一个正整数n (1<=n<=15)

    接下来是一个(n+1)*(n+1)的矩阵,矩阵中的数均为不超过10000的正整数。矩阵的i行j列表示第i-1号城市和j-1号城市之间直接通路的时间。当然城市a到城市b的直接通路时间和城市b到城市a的直接通路时间不一定相同,也就是说道路都是单向的。

    输出描述 Output Description

    一个正整数表示最少花费的时间

    样例输入 Sample Input
    3
    0 1 10 10
    1 0 1 2
    10 1 0 10
    10 2 10 0
    样例输出 Sample Output

    8

    数据范围及提示 Data Size & Hint

    1<=n<=15

    这道题很容易想到状压dp,首先跑一遍floyd求出各个点之间的最短路,然后dp。

    状态是dp[i][j]表示状态为i(二进制,表示是否访问过每个点),在位置j时的最短路。

    转移就是:dp[i][j]=min(dp[i-(1<<v)][u]+grid[u][v],dp[i][j]),其中v是当前位置,u是上一个状态的位置。

    需要注意的是dp的顺序应该是由含1的个数少的二进制到1的个数高的二进制;由于最开始就在0位置,所以dp[(1<<n)-1][0]不可能被转移到,所以最后的答案应该是ans=min(ans,dp[(1<<n)-1][i]+grid[i][0]),其中0<=i<n。

    详见代码:

    #include<iostream>
    #include<cstring>
    #include<vector>
    #include<queue>
    #include<algorithm>
    #include<cstdio>
    #include<climits>
    #define INF INT_MAX
    #define MAX_S 1<<16
    #define MAX_N 17
    using namespace std;
    
    struct node
    {
        int val,num;
        node(int v,int n)
            {val=v;num=n;}
        node(){}
    };
    
    node one[MAX_S];
    int grid[MAX_N][MAX_N];
    int n;
    int dp[MAX_S][MAX_N];
    int numOfOne(int x)
    {
        int res=0;
        for(int i=0;i<n;i++)
            if((x>>i)&1)res++;
        return res;
    }
    
    void floyd()
    {
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                for(int k=0;k<n;k++)
                    grid[i][j]=min(grid[i][j],grid[i][k]+grid[k][j]);
    }
    
    bool cmp(node a,node b)
    {
        return a.num<b.num;
    }
    
    int main()
    {
        scanf("%d",&n);
        n++;
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                scanf("%d",&grid[i][j]);
        int totS=1<<n;
        for(int i=0;i<totS;i++)one[i]=node(i,numOfOne(i));
    
        for(int i=0;i<totS;i++)
            for(int j=0;j<n;j++)
                dp[i][j]=INF;
    
        floyd();
        sort(one,one+totS,cmp);
        dp[1][0]=0;
        for(int i=0;i<totS;i++)
        {
            int s=one[i].val;
            for(int v=0;v<n;v++)
            {
                if(!((s>>v)&1))continue;
                int t=s-(1<<v);
                int tmp=INF;
                for(int u=0;u<n;u++)
                {
                    if((!((t>>u)&1))||dp[t][u]==INF)continue;
                    tmp=min(tmp,dp[t][u]+grid[u][v]);
                }
                if(tmp!=INF)
                    dp[s][v]=tmp;
            }
        }
        int ans=INF;
        for(int i=0;i<n;i++)
            ans=dp[totS-1][i]==INF?ans:min(ans,dp[totS-1][i]+grid[i][0]);
        cout<<ans<<endl;
        return 0;
    }
    


  • 相关阅读:
    day 66 ORM django 简介
    day 65 HTTP协议 Web框架的原理 服务器程序和应用程序
    jQuery的事件绑定和解绑 事件委托 轮播实现 jQuery的ajax jQuery补充
    background 超链接导航栏案例 定位
    继承性和层叠性 权重 盒模型 padding(内边距) border(边框) margin 标准文档流 块级元素和行内元素
    属性选择器 伪类选择器 伪元素选择器 浮动
    css的导入方式 基础选择器 高级选择器
    03-body标签中相关标签
    Java使用内存映射实现大文件的上传
    正则表达式
  • 原文地址:https://www.cnblogs.com/HarryGuo2012/p/4524040.html
Copyright © 2011-2022 走看看