(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;
}