poj3270

终于把这个很久以前拖下来的问题解决了

回忆一下,最少相邻交换次数等于逆序对数

这里求的是最少交换代价(非相邻元素也可以交换);

先考虑最少交换次数这个问题

首先把现在数列看成原数列{1,2,3……n}的一个置换

根据置换的理论,每一个置换都能拆成唯一的互不相交的循环

显然最小交换次数是在每个循环内部交换达成的

在一个包含元素数位x的循环内,交换成原数列的最小次数显然为x-1

最小交换次数就很明显了

而这里求的是最小交换代价,显然循环内部每个元素都要交换一次(除了只含一个元素的循环)

首先想到的是用每个循环内最小元素使循环内其他元素归位

注意还有一种情况,我们可以把整个序列里的最小元素a和这个循环里最小的b交换,然后用元素a与循环内其他元素交换,最后再把

a交换出循环(a和b交换)

最小代价就是取这两种方法较小的那一个

 1 var a,b:array[0..10010] of longint;
 2     f:array[0..100010] of longint;
 3     v:array[0..100010] of boolean;
 4     t,x,max,i,n,s,ans:longint;
 5 
 6 function min(a,b:longint):longint;
 7   begin
 8     if a>b then exit(b) else exit(a);
 9   end;
10 
11 procedure dfs(x:longint);   //找循环
12   begin
13     v[x]:=true;
14     ans:=ans+a[x];
15     inc(s);
16     if not v[b[x]] then dfs(b[x]);
17   end;
18 
19 begin
20   readln(n);
21   for i:=1 to n do
22   begin
23     readln(x);
24     if x>max then max:=x;
25     f[x]:=i;
26   end;
27   for i:=1 to max do  
28     if f[i]>0 then
29     begin
30       inc(t);
31       b[f[i]]:=t;
32       a[t]:=i;
33     end;
34 
35   for i:=1 to n do
36     if not v[i] then
37     begin
38       s:=0;
39       dfs(i);
40       ans:=ans+min((s-2)*a[i],(s+1)*a[1]+a[i]);
41     end;
42 
43   writeln(ans);
44 end.
View Code
原文地址:https://www.cnblogs.com/phile/p/4473188.html