• 补给【蓝桥杯 第十一届】【决赛】【A组】(压装DP+最短路+dp顺序和平行更新的处理)


    题目:“蓝桥杯”练习系统 (lanqiao.cn)

    思路:

    • n等于20,明显的提醒是要用到压装DP,
    • 要问从原点出发,每一个点都要至少走一次的最小距离
    • 压装可以看到由哪些点走过了,但是这个时候,我们还需要知道目前是那一个点
    • 于是就增加一个元素,二维dp,
    • 通过这个二维表示所有情况,进行更行.
    • 转移的时候就是:与他连接的边的子情况进行转移,
    • 但是有些情况 他跑过去了,还要跑回来着该怎么办呢?,就然他的儿子情况不表,不弄压装子节点,
    • 更新是有顺序的,对于子情况无所谓,因为都是已经更行过的了,但是不是子情况,需要s的平行转移,有一个更行顺序,不能有效的把那个情况更行出来,
    • 那就在平行倒着更新一遍,这要就能保证了 , 这2句话看待吧,比较好理解
    #include <bits/stdc++.h>
    using namespace std;
    #define ri register int 
    #define M 21
    
    int n,m;
    double dp[M][1<<21];
    struct dian{
        int x,y;
    }pp[M];
    struct node{
        int to;
        double val;
    };
    vector <node> p[M];
    double get(int a,int b)
    {
        return sqrt((pp[a].x-pp[b].x)*(pp[a].x-pp[b].x)+(pp[a].y-pp[b].y)*(pp[a].y-pp[b].y));
    }
    double dis[M];
    struct cmp{
        bool operator ()(const int a,const int b)const
        {
            return dis[a]>dis[b];
        }
    };
    int vis[M];
    void dj(int a)
    {
       for(ri i=1;i<=n;i++) dis[i]=1e9;
       dis[1]=0; 
       priority_queue<int,vector<int>,cmp> q;
       q.push(1);
       while(!q.empty())
       {
            while(!q.empty()&&vis[q.top()]) q.pop();
            if(q.empty()) break;
            int a=q.top();q.pop();
            vis[a]=1;
            for(ri i=0;i<p[a].size();i++)
            {
                int b=p[a][i].to;
                if(dis[b]>dis[a]+p[a][i].val)
                {
                    dis[b]=dis[a]+p[a][i].val;
                    q.push(b);
            }
        }
       }
    }
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0);
        
        cin>>n>>m;
        for(ri i=1;i<=n;i++)
        {
          cin>>pp[i].x>>pp[i].y;    
        }
        for(ri i=1;i<=n;i++)
        {
            for(ri j=i+1;j<=n;j++)
            {
                if(get(i,j)<=m)
                {
                    node t;
                    t.to=j;t.val=get(i,j);
                    p[i].push_back(t);
                    t.to=i;
                    p[j].push_back(t);
                }
            }
        }
        for(ri i=1;i<(1<<n);i++)
        {
            for(ri j=1;j<=n;j++)
            {
                dp[j][i]=1e9;
            }
        }
        dp[1][1]=0;
        for(ri i=1;i<(1<<n);i++)
        {
            for(ri j=1;j<=n;j++)
            {
                if((i&(1<<(j-1)))==0) continue;
                for(ri k=0;k<p[j].size();k++)
                {
                    int b=p[j][k].to;
                    if((i&(1<<(b-1)))==0) continue;
                    dp[j][i]=min(dp[j][i],dp[b][i^((1<<(j-1)))]+p[j][k].val);
                    dp[j][i]=min(dp[j][i],dp[b][i]+p[j][k].val);
                }
            }
            for(ri j=n;j>=1;j--)
            {
                if((i&(1<<(j-1)))==0) continue;
                for(ri k=0;k<p[j].size();k++)
                {
                    int b=p[j][k].to;
                    if((i&(1<<(b-1)))==0) continue;
                    dp[j][i]=min(dp[j][i],dp[b][i^((1<<(j-1)))]+p[j][k].val);
                    dp[j][i]=min(dp[j][i],dp[b][i]+p[j][k].val);
                }
            }
        }
        dj(1);
        double ans=1e9;
        for(ri i=1;i<=n;i++)
        {
            //cout<<dp[i][(1<<n)-1]+dis[i]<<endl;
            ans=min(ans,dp[i][(1<<n)-1]+dis[i]);
        }
        cout<<fixed<<setprecision(2)<<ans;
        
    } 
    View Code

    后记:

    • 用压装dp时,一定要看这个压装状态是不是合理的,本题要判断 i 节点和 j 节点都要在那个状态内很重要!!!!!
    • 对于DP顺序对相同状态下的转移一定要特别注意.
  • 相关阅读:
    Dev gridControl 按回车增加一行
    Web自动化----常见组件操作
    Web自动化----切换(iframe,浏览器窗口,alret)
    Web自动化----元素等待方法(显式等待和隐式等待)
    Web自动化----模拟动作(鼠标,快捷键,拖拽)
    MySQL的20条基本优化 加参考资料
    国内IT技术博客对比
    博客客户端文章测试
    QQ登录网站接入
    微信公众号本地开发调试工具
  • 原文地址:https://www.cnblogs.com/Lamboofhome/p/16375479.html
Copyright © 2020-2023  润新知