Cow Sorting && Permutations(poj 3270 && 2369)
阿新 • • 發佈:2019-02-05
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; }