zoukankan      html  css  js  c++  java
  • 【思维】建图+排列组合+预处理+最短路—— 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<<'
    ';
    } 
  • 相关阅读:
    POJ 1328 Radar Installation
    POJ 1700 Crossing River
    POJ 1700 Crossing River
    poj 3253 Fence Repair (贪心,优先队列)
    poj 3253 Fence Repair (贪心,优先队列)
    poj 3069 Saruman's Army(贪心)
    poj 3069 Saruman's Army(贪心)
    Redis 笔记与总结2 String 类型和 Hash 类型
    数据分析方法有哪些_数据分析方法
    数据分析方法有哪些_数据分析方法
  • 原文地址:https://www.cnblogs.com/zsben991126/p/13031744.html
Copyright © 2011-2022 走看看