模拟退火——leetcode

1815. 得到新鲜甜甜圈的最多组数 - 力扣(LeetCode)

class Solution {
public:
    int batchSize;
    int n;
    int ans = 0;
    vector<int> groups;
    int energy()
    {
        int res = 1;
        for (int i = 0, s = 0; i < n; i ++ ) {//计算是否有剩余
            s = (s + groups[i]) % batchSize;
            if (!s && i < n - 1) res ++ ;
        }
        ans = max(ans, res);
        return -res;
    }
    void th()
    {
        srand(time(NULL));//很重要
        random_shuffle(groups.begin(), groups.end());
        for(double t = 1e6; t > 1e-6; t *= 0.96)
        {
            int a = rand() % n, b = rand() % n;
            int ea = energy();
            swap(groups[a], groups[b]);
            int eb = energy();
            int dt = eb - ea;
            if(exp(-dt / t) > (double)rand() / RAND_MAX) continue;
            swap(groups[a], groups[b]);
        }
    }
    int maxHappyGroups(int _batchSize, vector<int>& _groups) {
        //调整groups的顺序,使最多人开心
        batchSize = _batchSize;
        groups = _groups;
        n = groups.size();
        for(int i = 0; i < 40; i ++ )
        th();
        return ans;
    }
};

1723. 完成所有工作的最短时间 - 力扣(LeetCode)

class Solution {
public:
    int ans = INT_MAX;
    vector<int> jobs;
    int energy(int k)
    {
        int n = jobs.size();
        vector<int> s(k);
        for(int i = 0; i < n; i ++ )//对于每项工作,找到一个最闲的工人分配
        {
            int kk = 0;
            for(int j = 1; j < k; j ++ )
                if(s[j] < s[kk]) kk = j;
            s[kk] += jobs[i];
        }
        int res = 0;
        for(auto &x : s)
            res = max(x, res);//找到最大工作时间
        ans = min(ans, res);
        return res; //能量越小越好 
    }
    void th(int k)
    {
        int n = jobs.size();
        double T = 10000;//一个很高的温度
        random_shuffle(jobs.begin(), jobs.end());//产生随机的工作分配顺序
        while(T > 1e-4) //降温过程
        {
            T *= 0.92;
            int a = rand() % n, b = rand() % n;
            int ea = energy(k);
            swap(jobs[a], jobs[b]);
            int eb = energy(k);
            int dt = eb - ea;
            if(dt <= 0 || exp(-dt / T) > rand() / RAND_MAX) continue;//以一定概率接受
            swap(jobs[a], jobs[b]);//不接受
        }
    }
    int minimumTimeRequired(vector<int>& _jobs, int k) {
        //每个工人至少分配一个工作
        jobs = _jobs;
        for(int i = 0; i < 7; i ++ )
        th(k);
        return ans;
    }
};

1879. 两个数组最小的异或值之和 - 力扣(LeetCode)

class Solution {
public:
    vector<int> nums1, nums2;
    int n;
    int ans = INT_MAX;
    int energy()
    {
        int res = 0;
        for(int i = 0; i < n; i ++ )
            res += nums1[i] ^ nums2[i];
        ans = min(ans, res);
        return res;//越小越好
    }
    void th()
    {
        srand(time(NULL));
        random_shuffle(nums1.begin(), nums1.end());
        for(double t = 1e6; t > 1e-5; t *= 0.99)
        {
            int a = rand() % n, b = rand() % n;
            int ea = energy();
            swap(nums2[a], nums2[b]);
            int eb = energy();
            int dt = eb - ea;
            if(dt < 0) continue;
            if(exp(-dt / t) > (double)rand() / RAND_MAX) continue; //恶化了,恶化的越大,越要回去
            swap(nums2[a], nums2[b]);
        }
    }
    int minimumXORSum(vector<int>& _nums1, vector<int>& _nums2) {
        nums1 = _nums1;
        nums2 = _nums2;
        n = nums2.size();
        for(int i = 0; i < 10; i ++ )
        th();
        return ans;
    }
};

1655. 分配重复整数 - 力扣(LeetCode)

class Solution {
public:
    vector<int> nums;
    vector<int> quantity;
    int n;
    int ans = 0;
    int m;
    int energy()
    {
        vector<int> tmp = nums;
        int res = 0;
        for(int i = 0; i < m; i ++ )// 对于每个人
        {
            int flag = false;
            for(int j = 0; j < n; j ++ )//找到第一个可以拿的数字
            {
                if(tmp[j] >= quantity[i])
                {
                    flag = true;
                    tmp[j] -= quantity[i];
                    break;
                }
            }
            if(flag) res ++;
        }
        ans = max(ans, res);
        return res;//能量大的好
    }
    void th()
    {
        srand(time(NULL));
        random_shuffle(nums.begin(), nums.end());
        for(double t = 1e5; t > 1e-5; t *= 0.95)
        {
            int a = rand() % n, b = rand() % n;
            int ea = energy();
            swap(nums[a], nums[b]);
            int eb = energy();
            int dt = ea - eb;
            if(dt < 0) continue;
            if(exp(-1 * dt / t) > rand() / RAND_MAX) continue;
            swap(nums[a], nums[b]);
        }
    }
    bool canDistribute(vector<int>& _nums, vector<int>& _quantity) {
        //分配相同整数
        vector<int> mp(1001);
        quantity = _quantity;
        sort(quantity.begin(), quantity.end(), greater<int>());//从大到小排序, 非常关键,为了尽可能的增加全部都分配好的概率,先解决数量大的
        m = quantity.size();
        for(auto x: _nums)
            mp[x] ++;
        for(int i = 1; i <= 1000; i ++ )
        {
            if(mp[i])
                nums.push_back(mp[i]);
        
        }
        n = nums.size();
        for(int i = 0; i < 5; i ++ )
        th();
        return ans == m;
    }
};

1515. 服务中心的最佳位置 - 力扣(LeetCode)

class Solution {
public:
	double sum(double x, double y, vector<vector<int>>& positions) {
		int n = positions.size();
		double ans = 0;
		for (int i = 0; i < n; i++) {
			ans += sqrt(pow(x - positions[i][0], 2) + pow(y - positions[i][1], 2));
		}
		return ans;
	}
	double getMinDistSum(vector<vector<int>>& positions) {
		int n = positions.size();
		double step = 100;
		double x = positions[0][0];
		double y = positions[0][1];
		while (step > 1e-7) {
            bool flag = true;
            double rad = rand() % 360; 
            while(flag)
            {
                flag = false;
                double nx = x + step * cos(rad);
                double ny = y + step * sin(rad);
                if (sum(nx, ny, positions) < sum(x, y, positions)) 
                {
                    x = nx;
                    y = ny;
                    flag = true;
                }    
            }
			step *= 0.85;
		}
		return sum(x, y, positions);
	}
};

爬山法

class Solution {
private:
    static constexpr int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

public:
    double getMinDistSum(vector<vector<int>>& positions) {
        double eps = 1e-7;
        double step = 1;
        double decay = 0.5;
        
        int n = positions.size();
        
        double x = 0.0, y = 0.0;
        for (const auto& pos: positions) {
            x += pos[0];
            y += pos[1];
        }
        x /= n;
        y /= n;
        
        // 计算服务中心 (xc, yc) 到客户的欧几里得距离之和
        auto getDist = [&](double xc, double yc) {
            double ans = 0;
            for (const auto& pos: positions) {
                ans += sqrt((pos[0] - xc) * (pos[0] - xc) + (pos[1] - yc) * (pos[1] - yc));
            }
            return ans;
        };
        
        while (step > eps) {
            bool modified = false;
            for (int i = 0; i < 4; ++i) {
                double xNext = x + step * dirs[i][0];
                double yNext = y + step * dirs[i][1];
                if (getDist(xNext, yNext) < getDist(x, y)) {
                    x = xNext;
                    y = yNext;
                    modified = true;
                    break;
                }
            }
            if (!modified) {
                step *= (1.0 - decay);
            }
        }
        
        return getDist(x, y);
    }
};

1239. 串联字符串的最大长度 - 力扣(LeetCode)

class Solution {
public:
    vector<string> arr;
    int n;
    int ans = 0;
    bool book[27];
    int enengy()
    {
        int res = 0;
        memset(book, 0, sizeof book);
        for(int i = 0; i < n; i ++ )
        {
            int flag = true;
            for(auto c: arr[i])
            {
                if(book[c - 'a']) 
                {
                    flag = false;
                    break;
                };
                book[c - 'a'] = true;
            }
            if(flag) res += arr[i].size();
        }
        return res;
    }
    void th()
    {
        srand(time(NULL));
        random_shuffle(arr.begin(), arr.end());
        for(int t = 1e6; t > 1e-6; t *= 0.96)
        {
            int a = rand() % n, b = rand() % n;
            int ea = enengy();
            swap(arr[a], arr[b]);
            int eb = enengy();
            ans = max({ans, ea, eb});
            int dt = ea - eb;
            if(dt < 0) continue;
            if(exp(-1 * dt / t) >= rand() / RAND_MAX) continue;
            swap(arr[a], arr[b]);
        }
    }
    int maxLength(vector<string>& _arr) {
        for(auto s: _arr)
        {
            memset(book, 0, sizeof book);
            bool flag = true;
            for(auto c: s)
            {
                if(book[c - 'a']) 
                {
                    flag = false;
                    break;
                }
                book[c - 'a'] = true;
            }
            if(flag) arr.push_back(s);
        }
        n = arr.size();
        if(!n) return 0;
        for(int i = 0; i < 2; i ++ )
        th();
        return ans;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值