http://poj.org/problem?id=3270
题意:
给定N头牛的身高,要求你通过每次交换两头牛的位置使其按身高从小到大排序,身高各不相同。假设交换ai,aj两头牛的位置则花费的时间为ai + aj,求用最小的时间花费。
思路:
黑书P248详细解释。
cost += sum + Min((k – 2) * ti, ti + (k + 1) * minn);
前一个式子:sum + (k – 2) * ti,ti是所在置换群的最小值
比如:8 4 5 3 2 7
目标 2 3 4 5 7 8,里边有两个置换群(8 2 7)(4 3 5)(这里是每个置换都可以写成若干互不相交的循环的乘积(黑书P247))
第一个置换群里的ti 是2,第二里ti是3
第一个式子:置换群里要使交换代价最小,必然是每次用最小的那个和其余大的交换
最少交换次数是k – 1, 所以除了ti, 其他元素只各参加一次,所以结果是:sum + (k – 2) * ti
第二个式子: 先用ti和所有n中的最小数minn交换,让minn执行交换工作,结束后,再把minn和ti交换回来
总共交换了k + 1次,期中k – 1次是初ti的其他数和minn交换,两次是ti和minn交换
所以结果是:sum + ti + (k + 1) * minn,
比如初始是:1 8 9 7 6
目标是 1 6 7 8 9
分解为(1) (8697),第一种算出来是: 6 + 7 + 8 + 9 + (4 – 2) * 6 = 42
第二种算出来是:6 + 7 + 8 + 9 + 6 + (4 – 1) * 1 = 41 ,
第二种比第一种多交换2次,所以当ti本来就是minn时用第二种会有额外支出,所以二者取小即
总花费cost = sum + ∑min{(ki - 2)*ti,ti + (ki + 1)*m};
ps:这学期开java课了,转变一下代码风格。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <set> #include <map> #include <string> #define CL(a,num) memset((a),(num),sizeof(a)) #define iabs(x) ((x) > 0 ? (x) : -(x)) #define Min(a,b) (a) > (b)? (b):(a) #define Max(a,b) (a) > (b)? (a):(b) #define ll long long #define inf 0x7f7f7f7f #define MOD 100000007 #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define test puts("<------------------->") #define maxn 100007 #define M 100007 #define N 10007 using namespace std; //freopen("din.txt","r",stdin); int a[N],b[N],mp[N*100]; bool vt[N*100]; int main(){ //freopen("din.txt","r",stdin); int n,i; scanf("%d",&n); int sum = 0,MIN = inf; for (i = 0; i < n; ++i){ scanf("%d",&a[i]); sum += a[i];//求总和 MIN = Min(a[i],MIN);//求整个序列的最小值 b[i] = a[i]; } sort(b,b + n);//b目标序列 a与b形成置换 CL(vt,false);CL(mp,0); for (i = 0; i < n; ++i){ mp[a[i]] = b[i];//置换后建立关系 } for (i = 0; i < n; ++i){ int t = a[i]; int len = 0; int tMIN = inf; while (!vt[t]){ //找循环 //printf("%d ",t); vt[t] = true; len++; tMIN = Min(tMIN,t); t = mp[t]; } if (len > 0){ sum += Min((len - 2)*tMIN,tMIN + (len + 1)*MIN); } } printf("%d\n",sum); return 0; }