【POJ】3270.Cow Sorting

题解

用到一点群论的知识!
我们发现把操作写成一个置换后,一定是单个置换圈的内进行操作,把置换圈进行扩大的操作不优
我们有两个办法,一个是用全局最小的换进来,代替这个圈里最小的值,交换操作完成后再换出去,二是用圈里最小的换完一圈
就两个操作,计算后贪心即可

代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <set>
#include <cstring>
#include <ctime>
#include <map>
#include <algorithm>
#include <cmath>
#define MAXN 100005
#define eps 1e-8
//#define ivorysi
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long int64;
typedef double db;

int N;
int a[MAXN],ra[MAXN],pos[MAXN],num[MAXN],line[MAXN],cnt;
bool vis[MAXN];
int64 ans = 0;
void dfs(int u) {
	if(vis[u]) return;
	line[++cnt] = u;
	vis[u] = 1;
	dfs(pos[num[u]]);
}
int main() {
#ifdef ivorysi
	freopen("f1.in","r",stdin);
#endif
	scanf("%d",&N);
	for(int i = 1 ; i <= N ; ++i) {scanf("%d",&a[i]);pos[a[i]] = i;num[i] = a[i];}
	sort(num + 1,num + N + 1);
	for(int i = 1 ; i <= N ; ++i) ra[num[i]] = i;
	cnt = 0;
	dfs(pos[num[1]]);
	for(int i = 1 ; i <= cnt ; ++i) {
		if(line[i] != pos[num[1]]) ans += num[1] + a[line[i]]; 
	}
	for(int i = 1 ; i <= N ; ++i) {
		if(!vis[i]) {
			cnt = 0;dfs(i);
			int minn = i;
			for(int j = 1 ; j <= cnt ; ++j) {
				if(a[line[j]] < a[minn]) minn = line[j];
			}
			int64 tmp1 = 0,tmp2 = 0;
			for(int j = 1 ; j <= cnt ; ++j) {
				if(line[j] != minn) tmp1 += a[minn] + a[line[j]];
			}
			for(int j = 1 ; j <= cnt ; ++j) {
				tmp2 += num[1] + a[line[j]];
			}
			tmp2 += num[1] + a[minn];
			ans += min(tmp1,tmp2);
		}
	}
	printf("%lld
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/ivorysi/p/9042369.html