Secret Santa 模拟

博客探讨如何通过贪心策略解决Secret Santa问题,确保每个人都能送给预想中的人礼物,同时保持结果的错排性质。算法从第一人开始按其意愿赠送,后续遍历过程中调整,以满足送礼条件。

传送门
每个人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;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值