51NOD 1125(交换机器最小代价) (贪心) 思想 !思想!
题目链接: https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1125
基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题
有N台机器重量各不相等,现在要求把这些机器按照重量排序,重量从左到右依次递增。移动机器只能做交换操作,但交换机器要花费一定的费用,费用的大小就是交换机器重量的和。例如:3 2 1,交换1 3后为递增排序,总的交换代价为4。给出N台机器的重量,求将所有机器变为有序的最小代价。(机器的重量均为正整数)
Input
第1行:1个数N,表示机器及房间的数量。(2 <= N <= 50000) 第2 - N + 1行:每行1个数,表示机器的重量Wi。(1 <= Wi <= 10^9)
Output
输出最小代价。
Input示例
3 3 2 1
Output示例
4
首先 数据量 并不弱, 5w*10^9 因此 必然要用 long long 第一次没
写 过了13组 第二次 成员没用 longlong 过了18组 - . -
题目大意: 既然是交换顺序;
有两种思路:
在所有的 数据当中, 我们把几个有关联(这几个数交换得到正确位置)的数据放到一起, 组成一个小组, 这样 所有数据, 就分成了 好几个组 ,
然后 我们 在对每一个组扫描的时候, 每次只会影响到当前这个数所在的小组,对其他小组不会造成影响, 因此对于每一个小组
有两种操作实现方式,:
一个是 直接小组内成员交换, 另一个就是,我们借助另外一个特殊值,用特殊值依次实现交换,(这个值是特殊值,为了使重量最小, 所以这个特殊值必须是 全部数据中 最小的那个) 然后 两种方式比较 选择当前小组 中 最合适的方法;
一是 用当前组下 小组内成员进行交换;
二是 借助外力实现, 依次交换;
每次 我们选择 两个中最小的方法 比较 并且要注意; 方法二中; 腾位子的 要多交换两次; for 循环的目的,就是为了解决 多组的问题;
#include <iostream> #include <queue> #include <string> #include <cstring> #include <cmath> #include <stdio.h> #include <algorithm> typedef long long ll; using namespace std; const int MAXN=50100; struct mac{ ll we; ll col;//位置 } a[MAXN]; int n; int vis[MAXN]; ll pre; int cmp(mac a,mac b) { return a.we<b.we; } ll change(int i)// 当前状态下最小换的 { ll sum=0; ll x,y,cont=0; x=a[i].we; y=a[i].col; while(i!=y) { sum+=a[y].we; vis[y]=1; y=a[y].col; cont++; } sum=sum+min((cont*x),(pre*(cont+2)+x*2)); return sum; } int main() { int i,j; while(cin>>n) { memset(a,0,sizeof(a)); memset(vis,0,sizeof(vis)); for(i=1;i<=n;i++) { cin>>a[i].we; a[i].col=i; } sort(a+1,a+n+1,cmp); ll sum=0; pre=a[1].we; for(i=1;i<=n;i++) { if(!vis[i]) { vis[i]=1; sum+=change(i); } } cout<<sum<<endl; } return 0; }
123
岂曰无衣?与子同袍。王于兴师,修我戈矛。与子同仇!
岂曰无衣?与子同泽。王于兴师,修我矛戟。与子偕作!
岂曰无衣?与子同裳。王于兴师,修我甲兵。与子偕行!