置換羣 ,找到共有幾組數不斷交換,求最小公倍數
例如:1 2 3 4 5 6 7 8 9 10這組,變換一次爲
10
7 8 9
4 5 6
1 2 3
即: 10 7 4 1 8 5 2 9 6 3
可觀察得:
1 3 4 10
2 7
5 6 8 9
這三組分別一直循環變換,結果即找 4,2, 4 的最小公倍數
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int mit[810][810], num[810], n, k;
bool vis[810];
long long gcd(long long x,long long y)
{
for(long long t;(t=x%y);x=y,y=t);
return y;
}
int main(){
// freopen("1.txt", "r", stdin);
long long i, j, r, c, ans, mm, tmp;
while( scanf("%d%d", &n, &k)&& !(n==0 && k==0 ) ){
if( n<= k) {
printf("1\n");
continue;
}
r= n/k;
c= n%k;
//memset(mit, -1, sizeof( mit));
memset( vis, false, sizeof( vis));
if( c==0) r--;
for( i=r, ans= 0; i>=0; i--){
for( j= 0; j<k; j++){
mit[i][j]= ans++;
}
}
for( i= 0, ans= 0; i<k; i++){
if( mit[0][i]< n) num[ans++]= mit[0][i];
for( j= 1; j<= r; j++){
num[ans++]= mit[j][i];
}
}
ans= 1;
for (i=0; i<n; i++){
//找到共有幾組數不斷交換,求最小公倍數
if( vis[i]) continue;
vis[i]= true;
tmp= num[i];
mm= 1;
while( !vis[tmp]){//cout<<i<<endl;
vis[tmp]= true;
tmp= num[tmp];
mm++;
}
tmp= gcd(mm, ans);
ans= ans/tmp*mm;
}
printf("%I64d\n", ans);
}
return 0;
}