[學習筆記] 隨機化貪心
阿新 • • 發佈:2022-03-01
簡介
如果題目要求最優解,但難以按照某個規則貪心求出最優解,也無法使用動態規劃等演算法。可以考慮隨機貪心,將輸入資料隨機打亂,然後從前到後按照某種方式貪心,多次隨機求最優值。
還可以結合多種不同的貪心規則,每次使用不同的貪心方法,不斷逼近最優值。
一般可以用在出題人無法輕易掌控某個輸入時得到的輸出
型別的題目,隨機情況下可以避免出題人的刻意卡。同時,隨機化貪心也可以加入權重,例如為直觀感受上更優的點提供更高的權重,更有機率排在序列的前面。
如何為更優的點提供更高的權值呢?如果某個點存在多個有關量,首先我們把有關量分類,類間的關聯性較小,類間的權值用加法。同類的量用比值定義法,越重要的量就在上面加次方就可以了。
成長快樂
由於出題人特意造一些有特殊性質的資料,所以本題應該不存在一個簡潔的做法,還是需要拼盤。
本人的隨機化演算法可以在 \(\tt luogu\) 上獲得 \(66\) 分(其中三個點輸出不合法被特殊資料卡),評測記錄
我們運用加權法,考慮給每個還沒有被吃掉的魚定這樣一個權值(引數是抄的別人的):
其中 \(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); }