1. 程式人生 > >Cow Sorting && Permutations(poj 3270 && 2369)

Cow Sorting && Permutations(poj 3270 && 2369)

poj3270:

題目大意是:有N頭牛,每個奶牛都有一個不同的脾氣指數L,現在要對這些牛按脾氣指數遞增的順序排列,但交換兩頭牛的代價是這兩頭牛的脾氣指數值的和,要求出最小代價。

關於置換群的題目,以前見過類似的題不會做……現在總算是知道方法了……

覺得右邊寫的不錯, 就是看他看懂的

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int a[10010], b[10010];
int hash[100010];
bool vis[10010];

int main (void)
{
	int n;
	while(scanf("%d", &n) != EOF)
	{
		int i, smallest = 0x3f3f3f3f;
		for(i = 0; i < n; i++)
		{
			scanf("%d", &a[i]);	
			if(smallest > a[i])
				smallest = a[i];
			b[i] = a[i];
		}
		sort(b, b + n);//b陣列存放目標的序列 
		for(i = 0; i < n; i++)
			hash[b[i]] = i;//hash記錄目標序列每個數存放的位置 
		memset(vis, 0, sizeof(vis));
		
		int visit = n;
		int ans = 0;
		while(visit)
		{//只要visit不為0,就說明還有沒有迴圈的奶牛
			int len = 0, sum = 0;
			int min = 0x3f3f3f3f, begin;//此次迴圈中的最小值和起始位置 
			begin = i = 0;
			while(vis[i])//找沒有遍歷過的下一個迴圈,開始沒寫這個……死迴圈 
				i ++;
			begin = i;//標記開始位置 
			while(1)
			{
				if(vis[i])
					continue;
				visit --;
				len ++;
				sum += a[i];
				vis[i] = 1;
				if(min > a[i])
					min = a[i];
				i = hash[a[i]];//i更新為在目標狀態中應在的位置
				
				if(i == begin)//又迴圈到起始位置了,跳出 
					break;
			}
			int m1 = sum + (len - 2) * min;
			int m2 = sum + min + (len + 1) * smallest;
			ans += m1 < m2 ? m1 : m2;//兩種交換方法 
		}
		printf("%d\n", ans);
	}
	
	return 0;
}

題目給一個序列,問至少置換多少次變成有序序列。

在序列中,每一次數字都有一個置換的週期,只要將每個數的置換的週期找到,然後取所有數週期的最小公倍數即可。

但是有一點我沒太明白……為什麼取最小公倍數的時寫成ans = ans * c / gcd(ans, c)就WA   而寫成ans = ans * (c / gcd(ans, c))或者ans = ans  / gcd(ans, c) × c 就沒錯啊……是精度的問題嗎……

#include <stdio.h>
#include <string.h>

int a[1010];
bool vis[1010];

int gcd(int x, int y)
{
	if(y == 0)
		return x;
	else
		return gcd(y, x % y);
}

int main (void)
{
	int n;
	while(scanf("%d", &n) != EOF)
	{
		memset(vis, 0, sizeof(vis));
		int i, j;
		for(i = 1; i <= n; i++)//注意從1開始賦值,或者從0開始賦值,每個數都減一 
			scanf("%d", &a[i]);
		int visit = n, begin;
		int ans = 1;
		i = 1;
		while(visit)
		{//visit控制迴圈幾次 
			visit--;
			while(vis[i])
				i ++;
			vis[i] = 1;
			j = a[i];
			int c = 1;//注意c從1開始 
			while(i != j)
			{
				j = a[j];
				c ++;
			}
			//printf("c = %d\n", c);
			ans = ans * (c / gcd(ans, c));
		}
		printf("%d\n", ans);
	}
	return 0;
}