把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷4212】外太空旅行(模拟退火)

点此看题面

大致题意: 给你一张图,让你从中选取最多的点,使这些点所构成的是完全图。

模拟退火

这道题可以用模拟退火来乱搞(或者随机化+\(dfs\)?)。

大体就是搞一个序列,定义其价值为从左往右、见到合法点立刻选所能选出的点数。

然后模拟退火,求出最大价值即为答案。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 50
#define swap(x,y) (x^=y^=x^=y)
#define Gmax(x,y) (x<(y)&&(x=(y)))
using namespace std;
int n,f[N+5][N+5];
class SimulatedAnnealing//模拟退火
{
	private:
		#define SA_TIME 100
		int ans,s[N+5],vis[N+5];
		I int Calc()//求出序列价值
		{
			RI i,j,res=0;for(i=1;i<=n;++i)
			{
				for(j=1;j^i;++j) if(vis[j]&&!f[s[i]][s[j]]) break;
				i^j?vis[i]=0:(++res,vis[i]=1);
			}return res;
		}
		I void Work()//模拟退火
		{
			RI i,x,y,res,nres;for(i=1;i<=n;++i) s[i]=i;random_shuffle(s+1,s+n+1),res=Calc(),Gmax(ans,res);//随机初始序列
			for(double tt=1e7;tt>1e-3;tt*=0.995)
			{
				W((x=rand()%n+1)==(y=rand()%n+1));swap(s[x],s[y]),nres=Calc(),Gmax(ans,nres);
				(nres>res||exp((res-nres)/tt)>1.0*rand()/RAND_MAX)?res=nres:swap(s[x],s[y]);
			}
		}
	public:
		I void Solve() {srand(20030909);for(RI i=1;i<=SA_TIME;++i) Work();printf("%d",ans);}
}S;
int main()
{
	RI i,x,y;scanf("%d",&n);W(~scanf("%d%d",&x,&y)) f[x][y]=f[y][x]=1;//读入,建图
	return S.Solve(),0;
}
posted @ 2019-07-10 10:50  TheLostWeak  阅读(186)  评论(0编辑  收藏  举报