置换的一项运用 poj3270

  关于置换,就是建立起映射关系。

  题目链接:http://poj.org/problem?id=3270

  题目大意:要求将每头牛从大到小排序,但是牛有怒气值,每移动两头牛,就需要付出这两头牛的怒气值作为代价。问,最小的怒气值是多少。

  在样例中建立起映射关系。

  

联想到数学里面的有关群的问题。使用最小的数去加途中经历过的牛的怒气值。

但是在遇到,最小的怒气值不在循环里面的时候, 最优解是不会根据上面的方法实现的。

例如:

根据上面的方法,得到的解为42。

而如果调用一下1去跟后面的循环去换,得到的解为41。

显然,可以根据最小值去得到最优解。

于是有两种方法:

第一种直接调用循环节里面的最小值,去跟循环里面的元素交换。

sum1=(minl+L(1))+(minl+L(2))+.......+(minl+L(m-1)) 

其中,设X为循环节的所有元素的集合,则L为X中除去最小值后的子集。minl为X集合中的最小值。

整理得:sum1=minl*(m-1)+sum(L)*(m-1)       其中sum(L) 为集合L的总和,minl为集合X的最小值。

 

第二种方法,整个集合中的最小元素不在循环节中,但是借用整个集合的最小元素与循环节中的最小元素调换两次,求出的解。

sum2=(min_all+X(1))+(min_all + X(2))+.......+(min_all + X(m)) +(min_all + minl)

其中,min_all为整个集合中最小的元素(不在循环节内), X集合为循环节的所有元素,minl为X集合中的最小元素。

整理得: sum2= min_all * (m+1) +sum(X) + minl

最优的结果只需要找出这两种方法中的最小值即可。

 

参考博客:https://www.cnblogs.com/kuangbin/archive/2012/09/03/2669013.html

 1 #include<iostream>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int maxn=10006;
 6 const int inf=0x3f3f3f3f;
 7 struct Point{
 8     int id,num;
 9     bool operator < (const Point b) const{
10         return this -> num < b.num;
11     }
12 }cow[maxn];
13 bool flag[maxn];
14 int MAXN;
15 
16 int solve(int n)
17 {
18     int ans=0;
19     memset( flag, 0, sizeof flag);
20     for(int i=1;i<=n;i++){
21         if(!flag[i]){
22             flag[i]=true; ///用flag判断是否在循环节中
23             int minl=cow[i].num;
24             int sum1=cow[i].num;
25             int next=cow[i].id;
26             int quan=1;
27             while(!flag[next]){
28                 flag[next]=true;
29                 quan++;
30                 if(minl>cow[next].num) minl=cow[next].num;
31                 sum1+=cow[next].num;
32                 next=cow[next].id;
33             }
34             ans+=min( sum1-minl+(quan-1)*minl, sum1+minl+(quan+1)*MAXN); 
35             ///在min的左边,计算结果为方法一。
36             ///min的右边,计算结果为方法二。
37         }
38     }
39     return ans;
40 }
41 
42 int main()
43 {
44     ios_base::sync_with_stdio(0); cin.tie(0);
45     cout.tie(0);
46     int n;
47     while( cin >> n){
48         MAXN=inf;
49         for(int i=1;i<=n;i++){
50             cow[i].id=i;
51             cin >> cow[i].num;
52             if(MAXN>cow[i].num) MAXN=cow[i].num;
53         }
54         sort( cow+1, cow+1+n); ///排序之后即可建立起映射关系
55         cout << solve(n) <<endl;
56     }
57     return 0;
58 }

 

posted @ 2018-05-17 14:39  flyer_duck  阅读(184)  评论(0编辑  收藏  举报