【思维】建图+排列组合+预处理+最短路—— 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<<'
';
} 
原文地址:https://www.cnblogs.com/zsben991126/p/13031744.html