题解 洛谷 P4044 【[AHOI2014/JSOI2014]保龄球】

(DP) 来做的话会很麻烦,细节会很多,考虑乱搞一些的做法。(n) 很小,答案和排列顺序有关,所以考虑模拟退火来解决本题。

产生新状态即为交换当前排列的两个位置。调参时可以采取降低退火次数,升高温度和降温系数来处理,这样正确性会高。

#include<bits/stdc++.h>
#define maxn 55
#define eps 1e-10
using namespace std;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
int n,m,ans,cnt=1000;
struct node
{
    int a,b;
}p[maxn];
int calc()
{
    int v=0;
    for(int i=1;i<=n+m;++i)
    {
        v+=p[i].a+p[i].b;
        if(p[i-1].a==10) v+=p[i].a+p[i].b;
        else if(p[i-1].a+p[i-1].b==10) v+=p[i].a;
    }
    return v;
}
void SA()
{
    double T=1000000,delta=0.9895;
	while(T>eps)
	{
		int x=rand()%(n+m)+1,y=rand()%(n+m)+1,v;
        while(x==y||(m&&(x==n||y==n))) x=rand()%(n+m)+1,y=rand()%(n+m)+1;
		swap(p[x],p[y]),v=calc();
		if(v>ans) ans=v;
		else if(exp((v-ans)/T)*RAND_MAX<rand()) swap(p[x],p[y]);
		T*=delta;
	}
}
int main()
{
    srand((long long)new char),read(n);
    for(int i=1;i<=n;++i) read(p[i].a),read(p[i].b);
    if(p[n].a==10) m=1,read(p[n+1].a),read(p[n+1].b);
    while(cnt--) SA();
    printf("%d",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/lhm-/p/13520115.html