1. 程式人生 > 其它 >[學習筆記] 隨機化貪心

[學習筆記] 隨機化貪心

簡介

如果題目要求最優解,但難以按照某個規則貪心求出最優解,也無法使用動態規劃等演算法。可以考慮隨機貪心,將輸入資料隨機打亂,然後從前到後按照某種方式貪心,多次隨機求最優值。

還可以結合多種不同的貪心規則,每次使用不同的貪心方法,不斷逼近最優值。

一般可以用在出題人無法輕易掌控某個輸入時得到的輸出型別的題目,隨機情況下可以避免出題人的刻意卡。同時,隨機化貪心也可以加入權重,例如為直觀感受上更優的點提供更高的權重,更有機率排在序列的前面。

如何為更優的點提供更高的權值呢?如果某個點存在多個有關量,首先我們把有關量分類,類間的關聯性較小,類間的權值用加法。同類的量用比值定義法,越重要的量就在上面加次方就可以了。

成長快樂

點此看題

由於出題人特意造一些有特殊性質的資料,所以本題應該不存在一個簡潔的做法,還是需要拼盤。

本人的隨機化演算法可以在 \(\tt luogu\) 上獲得 \(66\) 分(其中三個點輸出不合法被特殊資料卡),評測記錄

我們運用加權法,考慮給每個還沒有被吃掉的魚定這樣一個權值(引數是抄的別人的):

\[\frac{w_i}{t_i^2}+\frac{s_1}{d}+s_2 \]

其中 \(w_i\) 表示這隻蝦的權重,\(t_i\) 表示吃掉這隻蝦需要花費的時間,\(d\) 表示一開始和它的距離,\(s_1,s_2\) 是兩個在 \([1,10]\) 中的正整數,可以用 \(\tt mt19937\)

生成。

那麼我們按照這個權重選取最優的點即可,剩下的問題是計算相遇時間的問題,這篇部落格已經闡述的很清楚了,我只能說計算幾何是我的一生之敵,寫出來總是一堆鍋

#include <cstdio>
#include <random>
#include <cstdlib>
#include <iostream>
#include <ctime>
#include <cmath>
using namespace std;
#define db double
const int M = 100005;
const db inf = 1e18;
const db eps = 1e-12;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
db lim,ans,aw,ax,ay,nv,nw,nx,ny,nt;//nemo
db fw[M],fx[M],fy[M],fp[M],fq[M];int n,m,vis[M];
struct node{db t,x,y;int id;}a[M],b[M];
db sqr(db x) {return x*x;}
db dis(db a,db b,db c,db d) {return sqr(a-c)+sqr(b-d);}
db calc(int i)
{
	db x=fx[i]+nt*fp[i],y=fy[i]+nt*fq[i];
	if(fabs(nx-x)<eps && fabs(ny-y)<eps) return 0;
	db a=(sqr(fp[i])+sqr(fq[i]))-sqr(nv);
	db b=-2*((nx-x)*fp[i]+(ny-y)*fq[i]);
	db c=dis(x,y,nx,ny),dl=b*b-4*a*c,ans=inf;
	if(fabs(a)<eps) return (b>-eps)?inf:(-c/b);//a=0
	if(dl<eps) return inf;//no such solution
	dl=sqrt(dl);
	db x1=(-b-dl)/(2*a),x2=(-b+dl)/(2*a);
	if(x1>-eps) ans=x1;
	if(x2>-eps && x2<ans) ans=x2;
	return ans;
}
void work()
{
	mt19937 z(time(0));
	nw=aw;nx=ax;ny=ay;nt=0;
	int num=0,G=z()%10+1;
	for(int i=1;i<=n;i++) vis[i]=0;
	while(1)
	{
		int id=0;db mt=0,mk=-1;
		for(int i=1;i<=n;i++) if(fw[i]<nw && !vis[i])
		{
			db t=calc(i);
			db d=dis(nx,ny,fx[i]+fp[i]*nt,fy[i]+fq[i]*nt);
			db k=0;
			if(t<eps || sqrt(d)<eps) k=inf;
			else k=fw[i]/(t*t)+1/(G*sqrt(d))+z()%10;
			if(k>mk) mk=k,mt=t,id=i;
		}
		if(nt+mt>lim || !id) break;
		nt+=mt;vis[id]=1;
		nx=fx[id]+fp[id]*nt;
		ny=fy[id]+fq[id]*nt;
		nw+=fw[id];
		b[++num]=node{nt,nx,ny,id};
	}
	if(nw>ans)
	{
		ans=nw;m=num;
		for(int i=1;i<=m;i++) a[i]=b[i];
	}
}
signed main()
{
	freopen("nemo8.in","r",stdin);
	freopen("nemo8.out","w",stdout);
	scanf("%lf %lf %lf %lf %lf",&aw,&nv,&lim,&ax,&ay);
	n=read();
	for(int i=1;i<=n;i++)
	{
		scanf("%lf %lf %lf %lf %lf",
		&fw[i],&fx[i],&fy[i],&fp[i],&fq[i]);
	}
	while(1.0*clock()/CLOCKS_PER_SEC<=10) work();
	printf("%d\n%.6f\n",m,ans-aw);
	for(int i=1;i<=m;i++)
		printf("%.6f %.6f %.6f %d\n"
		,a[i].t,a[i].x,a[i].y,a[i].id);
}