最近学了置换群,然后就想着写几道
POJ - 1026 Cipher
题意:
题目意思是给一个置换,然后给一些字符串和一个整数k,要求对这些字符串进行k次置换
思路:
非常基础的题,要求置换k次,那么就把置换中的每一个环向右转 k − 1 k - 1 k−1次,然后再置换即可。
代码:
这里我写复杂了
#include<cstdio>
#include<algorithm>
#include<vector>
#include<iostream>
#include<cstring>
#define INF 0x3f3f3f3f
#define ll long long
#define pb push_back
#define eps 1e-8
#define endl '\n'
using namespace std;
const ll maxn = 1e4 + 5;
int n,p[maxn],k,np[maxn],cnt,X[205],Y[205];
char str[maxn],ans[maxn];
bool vis[maxn];
vector<int> R[maxn];
int main(){
while(~scanf("%d",&n) && n){
for(int i = 1; i <= n; i++)
scanf("%d",p + i);
cnt = 0;
for(int i = 1; i <= n; i++)vis[i] = 0;
for(int i = 1; i <= n; i++){
if(!vis[i]){
int x = p[i],cnt2 = 0;
R[++cnt].clear();
while(!vis[x]){
//找环,用vector存环,并用X,Y存每个数在第几个环,第几个位置
vis[x] = 1;
X[x] = cnt;
Y[x] = cnt2;
R[cnt].push_back(x);
x = p[x];
cnt2++;
}
}
}
while(scanf("%d",&k) && k){
getchar();
gets(str + 1);
int len = strlen(str + 1);
for(int i = 1; i <= n; i++){
int r = R[X[p[i]]].size(),idx = X[p[i]];
char &c = ans[R[idx][(Y[p[i]] + k - 1) % r]];//转k-1次后的位置
if(i <= len)
c = str[i];
else
c = ' ';
}
ans[n + 1] = '\0';
printf("%s\n",ans + 1);
}
printf("\n");
}
return 0;
}
POJ 3270 Cow Sorting
题意:
给了一些n不相同的数字,让你把这些数字进行从小到大排序,你可以每次交换两个数字,需要花费两个数字之和的代价,现在让求最小代价。
思路:
看到每个数字不相同就可以想到置换群了,首先先把所有的数字小到大按照1-n上号。然后就可以往置换的环上去想了。
比如: 4 2 1 3
按顺序写出他的环就是 4 3 1 2,这个顺序表示左侧数的位置在排序后应该是右侧的数。
那么就可以想到可以找到一个数,与所有数进行倒着交换比如:
swap(2,1),swap(2,3),swap(2,4)
可以发现在交换环的大小减一次时就可以完成排序
那么贪心的想法就是,找一个环最小的数与所有数进行交换(环内最小设为minn1,环所有数的和设为sum,环的大小设为r),花费为 s u m + ( r − 1 ) ∗ m i n n 1 sum +(r - 1)* minn1 sum+(r−1)∗minn1
但是这还不够,因为环外还有可能会有更小的数,所以如果引入一个环外的数有可能会造成更小的话费,引入环外的数的话就需要额外进行进行交换,即拿本环内的最小的先与环外的交换,然后再换回来,环内最小设为minn1,环外的设为minn2,环的大小设为r,环所有数的和设为sum,那么这种交换的花费就是 s u m + ( r + 1 ) ∗ m i n n 2 + m i n n 1 sum + (r+ 1) * minn2 + minn1 sum+(r+1)∗minn2+minn1
#include<cstdio>
#include<algorithm>
#include<vector>
#include<iostream>
#define INF 0x3f3f3f3f
#define ll long long
#define pb push_back
#define eps 1e-8
#define endl '\n'
using namespace std;
const ll maxn = 1e6 + 5;
int n,p[maxn],mp[maxn];
ll ans,minn = INF;
bool vis[maxn];
vector<ll> v;
struct node{
int val,idx;
}PP[maxn];
bool cmp(node a,node b){
return a.val < b.val;
}
void calculateValue(){
if(v.size() == 1)return;
ll sum = 0,len = v.size(),mi = INF;
for(int i = 0; i < len; i++)
sum += mp[v[i]],mi = min(mi,(ll)mp[v[i]]);
if(mi == minn)
ans += sum + (len - 2) * mi;
else
ans += min(sum + (len - 2) * mi, sum + (len + 1) * minn + mi);
}
int main(){
while(~scanf("%d",&n)){
for(int i = 1; i <= n; i++)vis[i] = 0;
ans = 0;
for(int i = 1; i <= n; i++)
scanf("%d",p + i),PP[i].val = p[i],PP[i].idx = i,minn = min(minn,(ll)p[i]);
sort(PP + 1,PP + n + 1,cmp);
for(int i = 1; i <= n; i++){
mp[i] = PP[i].val;
p[PP[i].idx] = i;
}
for(int i = 1; i <= n; i++){
if(!vis[i]){
int x = p[i];
v.clear();
while(!vis[x]){
v.push_back(x);
vis[x] = 1;
x = p[x];
}
calculateValue();
}
}
printf("%lld\n",ans);
}
return 0;
}