被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<<' '; }