Poj1379+poj 2539(模拟退火
题目:在矩形中有若干个点,求一个点使得所有点到该点的最小距离最大。
思路:这个是2008年顾研论文上的例题,可以比较简单地用模拟退火算法求解。所谓模拟退火就是先随机出若干个点,然后以某一特定步长尝试周围的解,而后逐渐缩小步长,知道步长小于特定值,跳出。这个算法虽然简单易行,但是其正确性并不是非常有保障,(不合理的随机方法可能会降低到达正确解的概率),而且几个主要参数的选取也主要看经验,毕竟对于一个随机化算法做出像论文中一样的严格评估还是比较困难的。。。。所以说即使实现完全正确,能否通过有时也是玄学的领域。。。。。尤其对于不太适合随机化的题。
ps:poj不能用time,一调用就re,查了一个多小时错才发现。。。。以后不用time了。。。
/* * @author: Cwind * http://www.cnblogs.com/Cw-trip/ * 蒟蒻只能做几个水题。。 */ //#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-3) #define IINF (1<<29) #define LINF (1ll<<59) #define FINF (1e100) #define INF 1000000000 const double pi=acos(-1.0); typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> P; inline double dis(double x1,double y1,double x2,double y2){ return sqrt(sq(x1-x2)+sq(y1-y2)); } int T; int X,Y,M; const int L=30; double zx[1005],zy[1005]; int main(){ freopen("/home/files/CppFiles/in","r",stdin); srand(rand()%100); cin>>T; while(T--){ cin>>X>>Y>>M; double delta=max(X,Y)/sqrt(M*1.0)+1,pos[30][2],d[30]; for(int i=0;i<M;i++){ double x,y; scanf("%lf%lf",&x,&y); zx[i]=x,zy[i]=y; } for(int i=0;i<30;i++){ pos[i][0]=(rand()%(1000+1)/1000.0*X); pos[i][1]=(rand()%(1000+1)/1000.0*Y); d[i]=FINF; for(int j=0;j<M;j++){ d[i]=fmin(d[i],dis(pos[i][0],pos[i][1],zx[j],zy[j])); } } while(delta>eps){ for(int i=0;i<30;i++){ for(int j=0;j<L;j++){ double rd=rand(); double dx=pos[i][0]+cos(rd)*delta,dy=pos[i][1]+sin(rd)*delta; if(dx>X||dx<0||dy>Y||dy<0) continue; double md=FINF; for(int k=0;k<M;k++){ md=fmin(md,dis(dx,dy,zx[k],zy[k])); } if(md>d[i]){ pos[i][0]=dx; pos[i][1]=dy; d[i]=md; } } } delta*=0.8; } double ans=0; int ansp=0; for(int i=0;i<30;i++){ if(ans<d[i]){ ans=d[i]; ansp=i; } } printf("The safest point is (%.1f, %.1f).\n",pos[ansp][0],pos[ansp][1]); } return 0; }
poj2539
题目:求使得一点到其他各点距离之和最小的点。
思路:和上题一样的写法,很顺利的1a了。。
/* * @author: Cwind * http://www.cnblogs.com/Cw-trip/ * 蒟蒻只能做几个水题。。 */ //#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-3) #define IINF (1<<29) #define LINF (1ll<<59) #define FINF (1e100) #define INF 1000000000 const double pi=acos(-1.0); typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> P; inline double dis(double x1,double y1,double x2,double y2){ return sqrt(sq(x1-x2)+sq(y1-y2)); } const int maxp=50; const int maxx=10000; int N; double c[105][2]; double p[maxp][2],d[maxp]; double delta=5000; int L=30; double a=0.8; int main(){ freopen("/home/files/CppFiles/in","r",stdin); srand(rand()%1000); cin>>N; for(int i=0;i<N;i++){ scanf("%lf%lf",&c[i][0],&c[i][1]); } for(int i=0;i<maxp;i++){ p[i][0]=(rand()%1001)/1000.0*maxx; p[i][1]=(rand()%1001)/1000.0*maxx; double sdis=0; for(int j=0;j<N;j++){ sdis+=dis(p[i][0],p[i][1],c[j][0],c[j][1]); } d[i]=sdis; } while(delta>eps){ for(int i=0;i<maxp;i++){ for(int j=0;j<L;j++){ double rd=rand(); double dx=p[i][0]+cos(rd)*delta,dy=p[i][1]+sin(rd)*delta; double sdis=0; for(int k=0;k<N;k++){ sdis+=dis(dx,dy,c[k][0],c[k][1]); } if(sdis<d[i]){ p[i][0]=dx; p[i][1]=dy; d[i]=sdis; } } } delta*=a; } double ans=1e100; for(int i=0;i<maxp;i++){ ans=fmin(d[i],ans); } printf("%.0f",ans); return 0; }