题目(7.7)链接: Minimum Cost Sort
思路:找交换的闭合回路,并且使用最小的元素作为交换媒介。当只移动闭合回路里的元素时,有成本函数 :
∑
i
=
0
n
w
i
+
(
n
−
2
)
×
m
i
n
(
w
i
)
\sum_{i=0}^n w_{i}+(n-2) \times min(w_{i})
∑i=0nwi+(n−2)×min(wi)。
当需要使用闭合回路以外的元素作为交换媒介时,有成本函数 :
∑
i
=
0
n
w
i
+
m
i
n
(
w
i
)
+
(
n
+
1
)
×
x
\sum_{i=0}^n w_{i} + min(w_{i}) + (n+1)\times x
∑i=0nwi+min(wi)+(n+1)×x
其中
w
i
表
示
闭
合
回
路
中
的
元
素
,
n
表
示
闭
合
回
路
中
的
元
素
个
数
,
x
表
示
整
个
输
入
中
的
最
小
元
素
w_{i}表示闭合回路中的元素,n表示闭合回路中的元素个数,x表示整个输入中的最小元素
wi表示闭合回路中的元素,n表示闭合回路中的元素个数,x表示整个输入中的最小元素,具体解法说明见《挑战程序设计-算法和数据结构》p144。
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int Max = 1005;
const int M = 10005;
int w[Max], s;
int b[Max];//排好序的数组,用于确定w中元素排好序后的位置
int t[M];//与b数组结合确定元素排好序后的位置
int visit[Max];//用于标记元素是否已被访问
int solve(int w[], int b[], int n)
{
memset(visit, 0, sizeof(visit));
for(int i=0; i<n; i++)//确定w中元素排好序后的位置
t[b[i]] = i;
int result = 0;
for(int i=0; i<n; i++)
{
if(visit[i]) continue;
int cur = i, sum = 0, num = 0, m = M;//cur为当前访问w中元素的下标,sum计算闭合回路的总和,num计算闭合回路的总元素,m计算闭合回路中的最小值。
while(!visit[cur])
{
visit[cur] = 1;
m = min(m, w[cur]);
sum += w[cur];
num++;
cur = t[w[cur]];//计算闭合回路的下一个元素的下标,也即排序后w[cur]应在的位置
}
if(num)
{
result += min(sum+(num-2)*m, sum+m+(num+1)*s);//两个公式求最小
}
}
return result;
}
int main()
{
int n;
s = M;
cin >> n;
for(int i=0; i<n; i++)
{
cin >> w[i];
b[i] = w[i];
s = min(s, w[i]);//求全局最小
}
sort(b, b+n);
cout << solve(w, b, n) << endl;
}