题意:
有n头牛,无序的排成一排,每个牛有一个权值w,现在要将牛按权值递增排序,每次可以交换两头牛的位置并且所需的代价是这两头牛的权值和,问使得牛权值按递增排序需要的最代价。
题解:
置换群的应用,每轮交换的最小代价要么就是指环内部取一个最小的作为踏板交换,要么就是在外部找一个最小的作为踏板交换,去两者的最小值。dfs出每个轮换,然后对每个轮换按上诉操作,最终累加得最优解。
#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define B(x) (1<<(x))
using namespace std;
typedef long long ll;
void cmax(int& a,int b){ if(b>a)a=b; }
void cmin(int& a,int b){ if(b<a)a=b; }
void cmax(ll& a,ll b){ if(b>a)a=b; }
void cmin(ll& a,ll b){ if(b<a)a=b; }
void add(int& a,int b,int mod){ a=(a+b)%mod; }
void add(ll& a,ll b,ll mod){ a=(a+b)%mod; }
const int oo=0x3f3f3f3f;
const int MOD=2012;
const int maxn=11000;
int a[maxn],b[maxn];
int vis[maxn];
int n;
struct Node{
int mi,cnt;
void Init(){mi=oo;cnt=0;}
}z[maxn];
int tol;
void dfs(int u){
for(int i=1;i<=n;i++){
if(a[i]==u&&!vis[i]){
vis[i]=1;
cmin(z[tol].mi,a[i]);
z[tol].cnt++;
dfs(b[i]);
}
}
}
int main(){
//freopen("E:\\read.txt","r",stdin);
int Min,sum;
while(scanf("%d",&n)!=EOF){
Min=oo;
sum=0;
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);
a[i]=b[i];
cmin(Min,a[i]);
sum+=a[i];
}
sort(b+1,b+1+n);
memset(vis,0,sizeof vis);
tol=0;
for(int i=1;i<=n;i++){
if(vis[i])continue;
vis[i]=1;
z[tol].Init();
z[tol].cnt++;
cmin(z[tol].mi,a[i]);
dfs(b[i]);
tol++;
}
for(int i=0;i<tol;i++){
sum+=min(z[i].mi*(z[i].cnt-2),(z[i].cnt+1)*Min+z[i].mi);
}
printf("%d\n",sum);
}
return 0;
}