随机乱搞算法

模拟退火

bzoj3680 吊打XXX

题目大意:给定一些绳子和绳子上的重量,求出最后绳结的坐标。

思路:这个位置就是广义费马点,就是所有点到这个点的距离*每个点的权值最小的点。模拟退火,各种调常数。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#define maxnode 10005
using namespace std;
struct use{
    double x,y,gi;
}ai[maxnode]={0},ans;
double minn=999999999999999LL;
int n;
double ran(){return rand()%1000/1000.0;}
double fang(double a){return a*a;}
double dis(use a,use b){return sqrt(fang(a.x-b.x)+fang(a.y-b.y));}
double calc(use a)
{
    int i;double j=0;
    for (i=1;i<=n;++i) j+=dis(a,ai[i])*ai[i].gi;
    if (j<minn){minn=j;ans=a;} return j;
}
void work(double t)
{
    use a,now=ans;int i;double j;
    while(t>0.01)
    {
        a.x=now.x+t*(ran()*2-1);
        a.y=now.y+t*(ran()*2-1);
        j=calc(now)-calc(a);
        if (j>0||exp(j/t)>ran()) now=a;
        t*=0.980;
    }
    for (i=1;i<=1000;++i)
    {
        a.x=ans.x+t*(ran()*2-1);
        a.y=ans.y+t*(ran()*2-1);
        calc(a);
    }
}
int main()
{
    int i,j;scanf("%d",&n);srand(23333);
    for (i=1;i<=n;++i)
    {
        scanf("%lf%lf%lf",&ai[i].x,&ai[i].y,&ai[i].gi);
        ans.x+=ai[i].x*1.0;ans.y+=ai[i].y*1.0;
    }ans.x/=n;ans.y/=n;
    work(500000);printf("%.3f %.3f\n",ans.x,ans.y);
}
View Code

 

随机增量

bzoj2823 信号塔

题目大意:给定一些点,求最小的覆盖所有点的圆。

思路:假定当前的圆是ans,穷举所有点,如果某个点i不能被覆盖,就把当前点设为圆心、半径为0;然后找之前的点j,如果在圆外,就让i、j为直径做圆;然后找j之前的点k,如果在圆外就让i、j、k的三角形的外接圆为ans。这个复杂度的分析,据说期望o(n)。

求三角形外接圆:设三个点为a(x1,y1)b(x2,y2)c(x3,y3),圆心o(x,y),向量ao=(x-x1,y-y1)、bo=(x-x2,y-y2),这两个向量长度相等,就有(x-x1)^2+(y-y1)^2=(x-x2)^2+(y-y2)^2;同理由(x-x1)^2+(y-y1)^2=(x-x3)^2+(y-y3)^2。

化简后就是解一个二元一次方程组,如果设bx=x2-x1,by=y2-y1,cx=x3-x1,cy=y3-y1,d=2*(bx*cy-by*cx),那么x=(cy*(bx*bx+by*by)-by*(cx*cx+cy*cy))/d,y=(bx*(cx*cx+cy*cy)-cx*(bx*bx+by*by))/d.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define eps 1e-8
#define maxm 500005
using namespace std;
struct point{
    double xi,yi;
}ai[maxm]={0};
struct circle{
    point c;double r;
};
int cmp(double x,double y){
    if (x-y>eps) return 1;
    if (x-y<-eps) return -1;
    return 0;
}
double sqr(double x){return x*x;}
double dis(point x,point y){return sqrt(sqr(x.xi-y.xi)+sqr(x.yi-y.yi));}
point center(point a,point b,point c){
    double bx=b.xi-a.xi,by=b.yi-a.yi;
    double cx=c.xi-a.xi,cy=c.yi-a.yi;
    double d=2*(bx*cy-by*cx);
    double xx=(cy*(sqr(bx)+sqr(by))-by*(sqr(cx)+sqr(cy)))/d+a.xi;
    double yy=(bx*(sqr(cx)+sqr(cy))-cx*(sqr(bx)+sqr(by)))/d+a.yi;
    return (point){xx,yy};
}
int main(){
    int n,i,j,k;circle ans;
    scanf("%d",&n);
    for (i=1;i<=n;++i) scanf("%lf%lf",&ai[i].xi,&ai[i].yi);
    ans=(circle){ai[1],0.0};
    for (i=1;i<=n;++i)
        if (cmp(dis(ai[i],ans.c),ans.r)>0){
            ans.c=ai[i];ans.r=0;
            for (j=1;j<i;++j)
                if (cmp(dis(ai[j],ans.c),ans.r)>0){
                    ans.c=(point){(ai[i].xi+ai[j].xi)*0.5,(ai[i].yi+ai[j].yi)*0.5};
                    ans.r=dis(ai[i],ai[j])*0.5;
                    for (k=1;k<j;++k)
                        if (cmp(dis(ai[k],ans.c),ans.r)>0){
                            ans.c=center(ai[i],ai[j],ai[k]);
                            ans.r=dis(ai[i],ans.c);
                        }
                }
        }printf("%.2f %.2f %.2f\n",ans.c.xi,ans.c.yi,ans.r);
}
View Code

 

pollard's pho

bzoj4522 密钥破解

题目大意:数论集合。

思路:先用pollard's pho分解N,用p和q算出r,求出e在r下逆元d,求c^d(mod N)。

注意:pollard‘s pho的时候可能返回0,这个时候要在用pollard’s pho做一遍(不能在返回的时候判断,那样可能死循环)。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#define LL long long
using namespace std;
LL ab(LL x){return (x<0LL ? -x : x);}
void gcd(LL a,LL b,LL &d,LL &x,LL &y){
    if (!b){d=a;x=1LL;y=0LL;return;}
    gcd(b,a%b,d,y,x);y-=a/b*x;}
LL mul(LL a,LL b,LL p){
    LL c=0LL;
    for (;b;b>>=1LL){
        if (b&1LL) c=(c+a)%p;
        a=(a+a)%p;
    }return c;}
LL mi(LL a,LL b,LL p){
    LL c=1LL;
    for (;b;b>>=1LL){
        if (b&1LL) c=mul(c,a,p);
        a=mul(a,a,p);
    }return c;}
LL pho(LL x,LL c){
    LL i,k,y,x0,d,a,b;
    i=1LL;k=2LL;
    y=x0=(LL)rand()%x;
    while(true){
        ++i;x0=(mul(x0,x0,x)+c)%x;
        gcd(ab(y-x0),x,d,a,b);
        if (d!=1LL&&d!=x) return d;
        if (i==k){y=x0;k+=k;}
    }
}
int main(){
    LL e,nn,c,d,n,p=0LL,q,r;
    scanf("%I64d%I64d%I64d",&e,&nn,&c);
    while(!p) p=pho(nn,rand()%(nn-1LL)+1LL);
    q=nn/p;r=(p-1LL)*(q-1LL);
    gcd(e,r,p,d,q);d=(d%r+r)%r;
    n=mi(c,d,nn);
    printf("%I64d %I64d\n",d,n);
}
View Code

 

posted @ 2015-09-03 17:34  Rivendell  阅读(356)  评论(0编辑  收藏  举报