• 【思维】建图+排列组合+预处理+最短路—— 2020 联想杯 E


     被string坑惨了。。

    使用string前记得如果要直接进行下标运算,如s[10]=‘a'这种,要记得先给string开空间,string s=string(100,'a') 这样

    首先预处理出原串中所有类型数对的个数,如12,13,14...这种

    考虑每种变换,都是在原串的基础上,通过映射得到的:所有的变换操作其实都是把一个 8 的排列映射到另一个 8 的排列上

    所以原串不论怎么变化,总共只有8!种状态,即8的全排列,那么我们以每种排列作为定点,每种变换操作作为边(边权是一次交换对应的代价)进行建图

    建好后的图以排列12345678 为起点,跑一次最短路,可以得到12345678到所有状态的最少变换代价,

    然后再求出每个状态对应的第二种代价(逆序对的代价,可以O(1)求出),再找到最小值即可

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define N 500005
    
    ll n,cnt[10][10],tot,P[10][10],C[10][10];
    char S[N];
    map<string,int>mp;
    vector<string>s;
    ll cost[N];
    
    ll calc(string &s){//排列s对应的消耗 
        //for(int i=1;i<=8;i++)cout<<s[i];
        //cout<<" ";
        ll res=0;
        for(int i=1;i<=8;i++)
        for(int j=1;j<=8;j++)if(s[i]>s[j])
            res+=cnt[i][j]*P[s[i]-'0'][s[j]-'0'];
        return res;
    }
    
    void prework(){
        for(int i=1;i<=8;i++){
            int num=0;
            for(int j=1;j<=n;j++)
                if(S[j]-'0'==i)num++;
                else cnt[i][S[j]-'0']+=num;
        }
        char a[10];
        for(int i=1;i<=8;i++)a[i]=i+'0';
        tot=0;
        do{
            ++tot;
            for(int i=1;i<=8;i++)s[tot][i]=a[i];
            mp[s[tot]]=tot;
        }while(next_permutation(a+1,a+1+8));
        
        for(int i=1;i<=tot;i++)
            cost[i]=calc(s[i]);    
            
    }
    
    struct Edge{
        ll to,nxt,w;
    }e[N<<2];
    int head[N],tt;
    void add(ll u,ll v,ll w){
        e[tt].to=v;e[tt].w=w;e[tt].nxt=head[u];head[u]=tt++; 
    }
    void build(){
        memset(head,-1,sizeof head);
        for(int k=1;k<=tot;k++){
            int u=k,v;
            for(int i=1;i<=8;i++)
            for(int j=i+1;j<=8;j++){
                swap(s[k][i],s[k][j]);
                v=mp[s[k]];
                add(u,v,C[s[k][i]-'0'][s[k][j]-'0']);        
                swap(s[k][i],s[k][j]);
            }
        }
    }
    
    ll d[N],vis[N];
    priority_queue<pair<ll,ll> >pq;
    void dijkstra(){
        memset(d,0x3f,sizeof d);
        d[1]=0;
        pq.push(make_pair(0,1));
        while(pq.size()){
            int u=pq.top().second;pq.pop();
            if(vis[u])continue; 
            vis[u]=1;
            for(int i=head[u];i!=-1;i=e[i].nxt){
                int v=e[i].to;
                if(!vis[v] && e[i].w+d[u]<d[v]){
                    d[v]=e[i].w+d[u];
                    pq.push(make_pair(-d[v],v));
                }
            }
        }    
    }
    
    int main(){
        s.resize(200000);
        for(int i=1;i<=100000;i++)s[i]=string(10,'0');
        
        cin>>n>>(S+1);
        for(int i=1;i<=8;i++)for(int j=1;j<=8;j++)cin>>P[i][j];
        for(int i=1;i<=8;i++)for(int j=1;j<=8;j++)cin>>C[i][j];
        
        prework();//预处理出所有排列对应的代价 
        build();//建图 
        dijkstra();//跑一次最短路 
        ll ans=1e18;
        for(int i=1;i<=tot;i++)if(d[i]+cost[i]<ans){
    //        for(int j=1;j<=8;j++)cout<<s[i][j];cout<<" ";
            ans=min(ans,d[i]+cost[i]);
        }
        cout<<ans<<'
    ';
    } 
  • 相关阅读:
    MEF程序设计指南一:在应用程序中宿主MEF
    Silverlight & Blend动画设计系列十三:三角函数(Trigonometry)动画之飘落的雪花(Falling Snow)
    【Silverlight】Bing Maps开发应用与技巧六:使用样式美化图钉(Pushpin)控件的ToolTip外观
    线程的两种类型
    几种VC++数据库开发技术的比较
    Never use AfxEndThread! 一个非常好的例子
    我的 Visual C++ 6.0学习网站
    DB2 基础: 日期和时间的使用
    Boost::Regex 使用方法 (英文)
    vc访问数据库 (并弹出数据源浏览窗口与用户交互)
  • 原文地址:https://www.cnblogs.com/zsben991126/p/13031744.html
Copyright © 2020-2023  润新知