HDU 3644

模拟退火算法。。。。

这道题,呃。我怎么感觉他就是随机的。同一个代码,时而AC,时而WA。其实还真的是随机的。呵呵呵呵呵。。。因为下降火太快了,没办法,而降得慢又会。。。TLE,虽然精度提高了。

敢问,还有什么好的方法?我是在做退火算法时遇到这个练手的。

#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <time.h>

using namespace std;
const int MAXN=55;
const double PI=3.141592653;
const double eps=1e-5;

#define zero(a) fabs(a)<eps

struct point {
	double x,y;
};
struct Segment{
	point a,b;
};

point p[MAXN]; int n; double ans; int cot;
point tar[MAXN]; double best[MAXN]; double R;

point operator -(point &u,point &v){
	point re;
	re.x=u.x-v.x; re.y=u.y-v.y;
	return re;
}

double dot(point &u,point &v){
	return u.x*v.x+u.y*v.y;
}

double dist(point tt){
	return sqrt(tt.x*tt.x+tt.y*tt.y);
}
double multi(point &u,point &v){
	return u.x*v.y-u.y*v.x;
}
/*
bool whether_in(point &t){
	double angle=0;
	for(int i=0;i<n;i++){
		point A=p[i]-t;
		point B=p[i+1]-t;
		angle+=acos(dot(A,B)/dist(A)/dist(B));
	}
	if(fabs(angle-PI*2)<1e-5)
	return true;
	return false;
}

*/

double xmul(point p0,point p1,point p2){
    return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}

bool online(point p1,point p2,point p){
    if(zero(xmul(p1,p2,p))&&((p.x-p1.x)*(p.x-p2.x)<eps&&(p.y-p1.y)*(p.y-p2.y)<eps))
        return true;
    return false;
}

inline bool across(Segment s1,Segment s2){
    if(xmul(s1.a,s1.b,s2.a)*xmul(s1.a,s1.b,s2.b)<eps)
        if(xmul(s2.a,s2.b,s1.a)*xmul(s2.a,s2.b,s1.b)<eps)
            return true;
    return false;
}

bool whether_in(point cen){
    int cnt=0;
    Segment s,e;
    s.a=cen;s.b.y=cen.y;s.b.x=20000.0;
    for(int i=0;i<n;i++){
        e.a=p[i];e.b=p[i+1];
        if(online(p[i],p[i+1],cen)) return false;
        if(zero(p[i].y-p[i+1].y)) continue;
        if(online(s.a,s.b,p[i])){
            if(p[i].y>p[i+1].y) cnt++;
        }
        else if(online(s.a,s.b,p[i+1])){
            if(p[i+1].y>p[i].y) cnt++;
        }
        else if(across(s,e))
            cnt++;
    }
    return cnt&1;
}

double count_d(point &tt){
	double mm=1e10; double tp;
	for(int i=0;i<n;i++){
		point A=tt-p[i];
		point B=p[i+1]-p[i];
		if(dot(A,B)<=0){
			 tp=dist(A);
		//	 cout<<"1"<<‘ ‘<<tp<<endl;
			 mm=min(mm,tp);
			 continue;
		}
		A=tt-p[i+1];
		B=p[i]-p[i+1];
		if(dot(A,B)<=0){
			tp=dist(A);
			mm=min(mm,tp);
		//	cout<<"2"<<‘ ‘<<tp<<endl;
			continue;
		}
		double area=multi(A,B);
		tp=fabs(area)/dist(p[i]-p[i+1]);
	//	cout<<"3"<<‘ ‘<<tp<<endl;
		mm=min(mm,tp);
	}
	return mm;
}

double getdouble(){
	double re=((rand()*rand())%1000000)*1.0/1e6;
	return re;
}

int main(){
	srand(time(0));
	while(scanf("%d",&n),n){
		cot=0;
		for(int i=0;i<n;i++)
		scanf("%lf%lf",&p[i].x,&p[i].y);
		scanf("%lf",&R);
		p[n]=p[0];
		point tmp;
		for(int i=0;i<n;i++){
		tmp.x=(p[i].x+p[i+1].x)/2;
		tmp.y=(p[i].y+p[i+1].y)/2;
		tar[cot++]=tmp;
		}
	//	cout<<cot<<endl;
		bool flag=false;
		for(int i=0;i<cot;i++){
			best[i]=0;
		}
	//	cout<<"YES"<<endl;
		double T=50;
		for(double t=T;t>1e-4;t*=0.55){
			for(int i=0;i<cot;i++){
				for(int j=0;j<10;j++){
					double td=getdouble();
					if(rand()&1) td*=-1;
					tmp.x=tar[i].x+td*t;
					td=getdouble();
					if(rand()&1) td*=-1;
					tmp.y=tar[i].y+td*t;
					if(whether_in(tmp)){
						td=count_d(tmp);
						if(td>best[i]){
							best[i]=td;
							tar[i]=tmp;
						}
						if(td>=R||fabs(td-R)<1e-4){
					//		cout<<tmp.x<<‘ ‘<<tmp.y<<endl;
					//		cout<<td<<endl;
							flag=true;
							break;
						}
					}
				}
				if(flag) break;
			}
			if(flag) break;
		}
		if(flag) printf("Yes\n");
		else printf("No\n");
	}
	return 0;
}

  

HDU 3644

时间: 2024-12-10 17:06:25

HDU 3644的相关文章

HDU 3644 模拟退火

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3644 题意:给定n个点的一个多边形,一个圆的半径,判断圆是否可以放在多边形里, 由于圆形坐标没确定,所以采用模拟退火法来算,不断地减小步长,选取n个点,点在多边形内采用穿线法判断, 精度很坑爹,调了一下午精度,在wa与tle之间徘徊20+次,吐血AC. 代码: /* *********************************************** Author :rabbit Crea

HDU - 3644:A Chocolate Manufacturer&#39;s Problem(模拟退火, 求多边形内最大圆半径)

pro:给定一个N边形,然后给半径为R的圆,问是否可以放进去.  问题转化为多边形的最大内接圆半径.(N<50): sol:乍一看,不就是二分+半平面交验证是否有核的板子题吗. 然而事情并没有那么简单.  因为我们的多边形可能是凹多边形,而前面的方法只对凸多边形有效. 学习了下模拟退火的算法,这个随机算法只在最小圆覆盖的时候写过. 这里再学一下,看起来更正宗一点的.  每次在当前点的附近(R)找是否能优化,而这个R慢慢变小,使得趋紧答案的趋势更精细. 判定点再多边形内:同样,不能用检验是否在每条

hdu 3644 记忆化搜索

题目:给出一个有向图,从1到n,每个结点有个权值,每走一步,分值为结点权值的LCM,而且每一步的LCM都要有变化,问到达N的时候分值恰好为K的路径有多少条 记忆化搜索,虽然做过很多了,但是一直比较慢,这次总结出几点 1.注意确定终点状态 2.状态的初始化 3.不可能状态的排除 代码是参考cxlove写的,kuangbin博客要是刷完了,下一个就刷他啦 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm>

【转】[专题学习][计算几何]

原文地址:http://www.cnblogs.com/ch3656468/archive/2011/03/02/1969303.html 基本的叉积.点积和凸包等东西就不多说什么了,网上一搜一大堆,切一些题目基本熟悉了就差不多了. 一些基本的题目可以自己搜索,比如这个blog:http://blog.sina.com.cn/s/blog_49c5866c0100f3om.html 接下来,研究了半平面交,思想方法看07年朱泽园的国家队论文,模板代码参考自我校大牛韬哥: http://www.o

并查集 -- HDU 1232 UVALA 3644

并查集: 1 int pa[maxn],Rank[maxn]; 2 ///初始化 x 集合 3 void make_set(int x) 4 { 5 pa[x]=x; 6 Rank[x]=0; 7 } 8 ///递归查找 x 所在的集合 9 int find_set(int x) 10 { 11 if(pa[x]!=x) pa[x]=find_set(pa[x]); 12 return pa[x]; 13 } 14 ///更新根节点,如果不更新可能会暴栈 15 void mix(int x,in

HDU 6203 ping ping ping [LCA,贪心,DFS序,BIT(树状数组)]

题目链接:[http://acm.hdu.edu.cn/showproblem.php?pid=6203] 题意 :给出一棵树,如果(a,b)路径上有坏点,那么(a,b)之间不联通,给出一些不联通的点对,然后判断最少有多少个坏点. 题解 :求每个点对的LCA,然后根据LCA的深度排序.从LCA最深的点对开始,如果a或者b点已经有点被标记了,那么continue,否者标记(a,b)LCA的子树每个顶点加1. #include<Bits/stdc++.h> using namespace std;

HDU 5542 The Battle of Chibi dp+树状数组

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5542 题意:给你n个数,求其中上升子序列长度为m的个数 可以考虑用dp[i][j]表示以a[i]结尾的长度为j的上升子序列有多少 裸的dp是o(n2m) 所以需要优化 我们可以发现dp的第3维是找比它小的数,那么就可以用树状数组来找 这样就可以降低复杂度 #include<iostream> #include<cstdio> #include<cstring> #include

hdu 1207 汉诺塔II (DP+递推)

汉诺塔II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4529    Accepted Submission(s): 2231 Problem Description 经典的汉诺塔问题经常作为一个递归的经典例题存在.可能有人并不知道汉诺塔问题的典故.汉诺塔来源于印度传说的一个故事,上帝创造世界时作了三根金刚石柱子,在一根柱子上从下往

[hdu 2102]bfs+注意INF

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2102 感觉这个题非常水,结果一直WA,最后发现居然是0x3f3f3f3f不够大导致的--把INF改成INF+INF就过了. #include<bits/stdc++.h> using namespace std; bool vis[2][15][15]; char s[2][15][15]; const int INF=0x3f3f3f3f; const int fx[]={0,0,1,-1};