P3052 [USACO12MAR]Cows in a Skyscraper G(模拟退火)

题目链接

思路:主要讲一下模拟退火的思路。

这个题目有一个贪心的假思路,就是从大到小排个序,然后从头开始取,当大于界限的时候就放到下一堆里。这样显然构不成最优解,因为或许有一些较大的值跟较小的值恰好能凑满的话可以比贪心更优。所以就会产生较大的数在前面的组成一堆会更好,这里使用随机交换的方法,如果此次交换更优那么就更新答案,如果不,就计算接受的概率,接受的话就更新当前解,不接受的话就再换回来。参数调整好,多交几发🤦‍♂️。

#include <bits/stdc++.h>
using namespace std;

int n, W, ans;
int w[20];
bool vis[20];

int getzu() {
	int res = 1;
	int now = 0;
	for(int i = 1;i <= n; i++) {
		if(now + w[i] > W) {
			now = w[i];
			res++;
		}
		else now += w[i];
	}
	return res;
}

void sa() {
	double T = 10000, D = 0.996;
	int cur = n;
	while(T > 1e-14) {
		int pos1 = rand() % n + 1;
		int pos2 = rand() % n + 1;
		swap(w[pos1], w[pos2]);
		int now = getzu();
		if(now < cur) {
			cur = now;
			if(ans > cur) ans = cur;
		}
		else if(exp(ans-now)/T*RAND_MAX > rand()) {
			cur = now;
		}
		else swap(w[pos1], w[pos2]);
		T *= D;
	}
}

void solve() {
	int num = 500;
	while(num--) {
		sa();
	}
}

int main() {
	srand(time(NULL));
	scanf("%d %d", &n, &W);
	ans = n;
	for(int i = 1;i <= n; i++) {
		scanf("%d", &w[i]);
	}
	solve();
	
	printf("%d\n", ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值