传送门
每个人i都想送礼物给a[i],i!=a[i],且结果b[i]从1~n,即错排,尽可能的让i送给a[i]
贪心,先让第一个想送给a[i]的i送给a[i],剩下随便排
再从头到尾扫一遍,让 送给自己的 i ,送给 本来想送给的 a[i],然后让之前送给 a[i]的 ii, 送给 i
#include <iostream>
#include <cstring>
#include <string>
#include<map>
#include<queue>
#include<set>
#include<algorithm>
#include<cmath>
#include<vector>
#define debug(a) cout<<#a<<"="<<a<<endl;
#define cd(a) scanf("%d", &a)
#define ll long long
#define PII pair<int, int>
#define _for(i, a, b) for (int i = a; i < b; i++)
#define For(i, a, b) for (int i = a; i <= b; i++)
#define foR(i, b, a) for (int i = b; i >= a; i--)
#define ms(a,b) memset(a, b, sizeof a)
#define gcd(a, b) __gcd(a, b)
#define lcm(a, b) a / gcd(a, b) * b
#define INF 0x3f3f3f3f
using namespace std;
const int N = 2e5 + 10, mod = 1e9 + 7;
int a[N], b[N],v[N];
void sov(){
int n;
cin >> n;
For(i, 1, n) v[i] = 0;
For(i,1,n){
cin >> a[i];
}
int ans = 0;
vector<int> lfi;
map<int, int> mp;
For(i,1,n){
if(!v[a[i]]){
ans++;
v[a[i]] = 1;
b[i] = a[i];
mp[a[i]] = i;
}else{
lfi.push_back(i);
}
}
int ct = 0;
For(i,1,n){
if(v[i]==0){
b[lfi[ct++]] = i;
}
}
For(i,1,n){
if(b[i]==i){
int ii = mp[a[i]];
b[i] = a[i];
b[ii] = i;
mp[a[i]] =i;
mp[i] = ii;
}
}
printf("%d\n",ans);
For(i,1,n){
printf("%d ",b[i]);
}
printf("\n");
}
signed main(){
int T;
cin >> T;
while(T--){
sov();
}
return 0;
}
博客探讨如何通过贪心策略解决Secret Santa问题,确保每个人都能送给预想中的人礼物,同时保持结果的错排性质。算法从第一人开始按其意愿赠送,后续遍历过程中调整,以满足送礼条件。
279

被折叠的 条评论
为什么被折叠?



