• CSU1129 送货到家 【状压dp】


    哈哈发现这道题竟然没有题解,于是我决定写一份!

    状压dp

    题目:

    懒惰的巫女Reimu因为各种原因在香霖堂的店主Rinnosuke那儿欠下了很多债,于是乎只好靠帮他在幻想乡中送货来偿还掉微不足道的一小部分。

    懒归懒,Reimu还是很聪明的,她希望送货的总路程尽可能的短,同时任何一个地方不经过两次。

    简而言之,便是在一张图上找一个边权和最小经过所有点恰好一次的封闭回路。

    Input

    多组输入数据。

    第一行为一个N(N<=15),即图上总共有多少个点。

    之后共N行以邻接矩阵格式输入边的数据。

    保证i->j与j->i的距离相同。

    Output

    每组数据仅一行,输出最小的封闭回路或者是“NoAnswer”。

    Sample Input

    5
    0 1 3 3 1
    1 0 1 3 3
    3 1 0 1 3
    3 3 1 0 1
    1 3 3 1 0
    

    Sample Output

    5

    是一道很典型的旅行商问题

    不同之处是,大白上的旅行商问题是一定会有答案的,而且是从0这个点开始,这道题可能会有no answer的情况并且不是从0开始

    当某个图从任意点出发都无法回到起点时,就输出noanswer

    因为用邻接矩阵输入,所以预处理将0设成INF表示无法连通

    dp数组不能太大 20的时候就爆内存了

    初始化ans为INF 跑了一圈还是INF的话说明没走通就是没结果

    刚开始把每个点作为起点都判了一遍 某一个无法连通的样例不知道为啥输出了结果

    后来赵木杉学长启发 发现因为是无向图 所以并不需要判断以每个点作为起点 只用判断从0开始就可以了

    因为要是能形成一个圈 以哪个为起点都是可以的 要是不能 以哪个为起点都是不行的

    代码如下

    #include <iostream>
    #include<stdio.h>
    #include<algorithm>
    #include<string>
    #include<cstring>
    #define INF 0x3f3f3f3f
    
    using namespace std;
    
    int n;
    long long edge[20][20],dp[1<<16][16];
    bool vis[20];
    
    long long rec(int s,int v,int now)
    {
        if(dp[s][v]>=0)
            return dp[s][v];
    
        if(s==(1<<n)-1&&v==now)
            return dp[s][v]=0;
    
        long long res=INF;
        for(int u=0;u<n;u++)
        {
            if(!(s>>u&1))
            {
                res=min(res,rec(s|1<<u,u,now)+edge[v][u]);
            }
        }
    
        return dp[s][v]=res;
    }
    
    
    int main()
    {
        while(scanf("%d",&n)!=EOF)
        {
            for(int i=0;i<n;i++)
            {
                for(int j=0;j<n;j++)
                {
                    scanf("%lld",&edge[i][j]);
                    if(edge[i][j]==0)
                    edge[i][j]=INF;
                }
            }
    
            memset(dp,-1,sizeof(dp));
    
            int cnt=0;
            for(int i=0;i<n;i++)
            {
                if(edge[0][i]==1)
                    cnt++;
            }
    
            long long ans=INF;
            ans=min(ans,rec(0,0,0));
            /*for(int i=0;i<n;i++)
            {
                ans=min(ans,rec(0,i,i));
            }
            */
    
            if(ans!=INF)
            printf("%lld
    ",ans);
            else
            printf("NoAnswer
    ");
        }
        return 0;
    }


    提供一组noanswer的样例吧

    4

    0 1 0 0

    1 0 2 4

    0 2 0 3

    0 4 3 0

  • 相关阅读:
    Redis Sentinel 哨兵模式
    Redis 读写分离
    Redis 分布式锁实现
    Redis 缓存的收益和成本
    Redis 实现排行榜
    Spring Boot 使用 Cache 缓存
    Spring Boot 整合 Redis
    Spring Boot 使用阿里巴巴 Druid 数据源
    Spring Boot 整合 JWT
    B1003
  • 原文地址:https://www.cnblogs.com/wyboooo/p/9643462.html
Copyright © 2020-2023  润新知