「ライブラリ」(2006/06/04 (日) 03:40:03) の最新版変更点
追加された行は緑色になります。
削除された行は赤色になります。
*平面幾何計算
class Double2D{
double x;
double y;
static final double EPS = 1.0E-9;
Double2D(double x,double y){
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object o){
Double2D p = (Double2D)o;
return x==p.x&&y==p.y;
}
public double squareDist(Double2D p){
return (x-p.x)*(x-p.x) + (y-p.y)*(y-p.y);
}
public double dist(Double2D p){
return Math.sqrt(this.squareDist(p));
}
// thisとpを通る半径rの円の中心
public Double2D[] centerOfPassingCircle1(Double2D p,double r){
if(this.dist(p)>r) return null; // 境界条件はテキトー
double a = p.x - x;
double b = p.y - y;
double d = this.dist(p);
double qx0 = x / 2 + p.x / 2 + Math.sqrt(r - d*d/4)*(-b)/d;
double qy0 = y / 2 + p.y / 2 + Math.sqrt(r - d*d/4)*a/d;
double qx1 = x / 2 + p.x / 2 - Math.sqrt(r - d*d/4)*(-b)/d;
double qy1 = y / 2 + p.y / 2 - Math.sqrt(r - d*d/4)*a/d;
Double2D[] ret = new Double2D[2];
ret[0] = new Double2D(qx0,qy0);
ret[1] = new Double2D(qx1,qy1);
return ret;
}
// 三点の作る三角形の面積
public static double squareOfTriangle(Double2D p1,Double2D p2,Double2D p3){
double x1 = p1.x-p2.x;
double x2 = p3.x-p2.x;
double y1 = p1.y-p2.y;
double y2 = p3.y-p2.y;
double s = (x1*y2-x2*y1)/2;
return Math.abs(s);
}
// 多角形の内部にあるかどうか 自己ループはないものとする
public static boolean inPolygon(ArrayList<Double2D> poly){
double acc = 0.0;
int n = poly.size();
for(int i=0;i<n-1;i++){
acc += arg(poly.get(i),poly.get(i+1));
}
acc += arg(poly.get(n-1),poly.get(0));
if(Math.abs(acc)<EPS) return false;
else return true;
}
// -Pi < theta < Pi の範囲で偏角を返す 複素数でいう Arg(p2/p1)
public static double arg(Double2D p1,Double2D p2){
double ax = p1.x;
double ay = p1.y;
double bx = p2.x;
double by = p2.y;
double theta = Math.atan2((ax*by-ay*bx)/(ax*ax+ay*ay),(ax*bx+ay*by)/(ax*ax+ay*ay));
return theta;
}
// 外接円の中心 Online Judge 検証なし 簡易検証あり
public static Double2D centerOfCircumscribingCircle(Double2D p1, Double2D p2, Double2D p3){
double x1 = p1.x, y1 = p1.y, x2 = p2.x, y2 = p2.y, x3 = p3.x, y3 = p3.y;
double det = (x1*(y2-y3)+x2*(y3-y1)+x3*(y1-y2));
if(Math.abs(det)<EPS) return null;
double sx =
-y1*(x2*x2+y2*y2-x3*x3-y3*y3)
-y2*(x3*x3+y3*y3-x1*x1-y1*y1)
-y3*(x1*x1+y1*y1-x2*x2-y2*y2);
double sy =
x1*(x2*x2+y2*y2-x3*x3-y3*y3)
+x2*(x3*x3+y3*y3-x1*x1-y1*y1)
+x3*(x1*x1+y1*y1-x2*x2-y2*y2);
return new Double2D(0.5*sx/det, 0.5*sy/det);
}
}
class Line{
double a;
double b;
double c;
static final double EPS = 1.0E-9;
Line(double a, double b, double c) {
this.a = a;
this.b = b;
this.c = c;
}
Line(Double2D p1,Double2D p2){
this.a = p1.y-p2.y;
this.b = -p1.x+p2.x;
this.c = -p1.x*(p1.y-p2.y)+p1.y*(p1.x-p2.x);
}
// 線分と線分の交点 ない場合は null
// 2線分が重なりをもつときは考えていない
public Double2D crossPoint(Line l){
// 平行
if(Math.abs(this.a*l.b-this.b*l.a)<EPS){
return null;
}
else{
double x = (-l.b*this.c+this.b*l.c)/(this.a*l.b-this.b*l.a);
double y = (l.a*this.c-this.a*l.c)/(this.a*l.b-this.b*l.a);
return new Double2D(x,y);
}
}
}
class Circle{
double x;
double y;
double r;
static final double EPS = 1.0E-9;
Circle(double x, double y, double r) {
this.x = x;
this.y = y;
this.r = r;
}
public double centerDist(Circle c){
return Math.sqrt((x-c.x)*(x-c.x)+(y-c.y)*(y-c.y));
}
// 2円の交点
public Double2D[] crossPoint1(Circle c){
double d = centerDist(c);
if(r+c.r > d) return null; // 境界条件はテキトー
double d1 = (d*d + r*r - c.r*c.r)/(2*d);
double ex = x + (c.x-x)*d1/d;
double ey = y + (c.y-y)*d1/d;
double l = Math.sqrt(r*r-d1*d1);
double lx = -(c.y-y)*l/d;
double ly = (c.x-x)*l/d;
Double2D[] ret = new Double2D[2];
ret[0] = new Double2D(ex+lx, ey+ly);
ret[1] = new Double2D(ex-lx, ey-ly);
return ret;
}
// 1点を通る接線
public Line[] tangentLine(Double2D p){
Line[] ret = new Line[2];
if(Math.abs((x-p.x)*(x-p.x)-r*r)<EPS){
ret[0] = new Line(1, 0, -p.x);
double m = ((y-p.y)*(y-p.y)-r*r)/(2*(x-p.x)*(y-p.y));
ret[1] = new Line(m, -1, -m*p.x+p.y);
}
else{
double m1 = ((x-p.x)*(y-p.y)+r*Math.sqrt((x-p.x)*(x-p.x)+(y-p.y)*(y-p.y)-r*r))/((x-p.x)*(x-p.x)-r*r);
double m2 = ((x-p.x)*(y-p.y)-r*Math.sqrt((x-p.x)*(x-p.x)+(y-p.y)*(y-p.y)-r*r))/((x-p.x)*(x-p.x)-r*r);
ret[0] = new Line(m1, -1, -m1*p.x+p.y);
ret[1] = new Line(m2, -1, -m2*p.x+p.y);
}
return ret;
}
}
class LineSegment{
Double2D p1;
Double2D p2;
static final double EPS = 1.0E-9;
LineSegment(double x1, double y1, double x2, double y2){
p1 = new Double2D(x1, y1);
p2 = new Double2D(x2, y2);
}
// 2線分が重なりをもつときは考えていない
public Double2D crossPoint(LineSegment ls){
Double2D p3 = ls.p1;
Double2D p4 = ls.p2;
if(fcompare(Math.max(p1.x, p2.x), Math.min(p3.x, p4.x))<0 ||
fcompare(Math.max(p3.x, p4.x), Math.min(p1.x, p2.x))<0 ||
fcompare(Math.max(p1.y, p2.y), Math.min(p3.y, p4.y))<0 ||
fcompare(Math.max(p3.y, p4.y), Math.min(p1.y, p2.y))<0) return null;
double dx00 = p2.x - p1.x;
double dy00 = p2.y - p1.y;
double dx01 = p3.x - p1.x;
double dy01 = p3.y - p1.y;
double dx02 = p4.x - p1.x;
double dy02 = p4.y - p1.y;
double dx10 = p4.x - p3.x;
double dy10 = p4.y - p3.y;
double dx11 = p1.x - p3.x;
double dy11 = p1.y - p3.y;
double dx12 = p2.x - p3.x;
double dy12 = p2.y - p3.y;
// 平行
if(Math.abs(dx00*dy10-dy00*dx10)<EPS){
if(p1.x==p3.x&&p1.y==p3.y) return p1;
if(p1.x==p4.x&&p1.y==p4.y) return p1;
if(p2.x==p3.x&&p2.y==p3.y) return p2;
if(p2.x==p4.x&&p2.y==p4.y) return p2;
}
if(fcompare((dx00*dy01-dx01*dy00)*(dx00*dy02-dx02*dy00), 0)<=0 &&
fcompare((dx10*dy11-dx11*dy10)*(dx10*dy12-dx12*dy10), 0)<=0){
Line l1 = new Line(p1, p2);
Line l2 = new Line(p3, p4);
return l1.crossPoint(l2);
}
else return null;
}
private int fcompare(double a, double b){
if(Math.abs(a-b)<EPS) return 0;
if(a>b) return 1;
else return -1;
}
}
*空間幾何計算
class Double3D{
double x;
double y;
double z;
Double3D(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public double dist(Double3D p){
double dx = p.x-this.x;
double dy = p.y-this.y;
double dz = p.z-this.z;
return Math.sqrt(dx*dx+dy*dy+dz*dz);
}
//determinant of matrix |a1 a2 a3| where a1,a2,a3 are column vectors
public static double det(Double3D a1,Double3D a2,Double3D a3){
double d1 = a1.x*(a2.y*a3.z-a2.z*a3.y);
double d2 = a1.y*(a2.x*a3.z-a2.z*a3.x);
double d3 = a1.z*(a2.x*a3.y-a2.y*a3.x);
return d1-d2+d3;
}
/* solution of linear equation
* where coefficient matrix is (a1 a2 a3) and c is constant vector
* when the solution is not unique, return null
*/
public static Double3D solveLinearEquation(Double3D a1,Double3D a2,Double3D a3,Double3D c){
double d = det(a1,a2,a3);
if(Math.abs(d)<1E-10) return null;
double o1 = det(c,a2,a3);
double o2 = det(a1,c,a3);
double o3 = det(a1,a2,c);
return new Double3D(o1/d,o2/d,o3/d);
}
/* center of circumcircle of Triangle pqr
* when p,q,r are on a line, return null
*/
public static Double3D centerOfCircumCircle(Double3D p,Double3D q,Double3D r){
double a11 = 2*(p.x-q.x);
double a12 = 2*(p.y-q.y);
double a13 = 2*(p.z-q.z);
double c1 = p.x*p.x+p.y*p.y+p.z*p.z-q.x*q.x-q.y*q.y-q.z*q.z;
double a21 = 2*(p.x-r.x);
double a22 = 2*(p.y-r.y);
double a23 = 2*(p.z-r.z);
double c2 = p.x*p.x+p.y*p.y+p.z*p.z-r.x*r.x-r.y*r.y-r.z*r.z;
double a31 = p.y*q.z+q.y*r.z+r.y*p.z-p.z*q.y-q.z*r.y-r.z*p.y;
double a32 = p.z*q.x+q.z*r.x+r.z*p.x-p.x*q.z-q.x*r.z-r.x*p.z;
double a33 = p.x*q.y+q.x*r.y+r.x*p.y-p.y*q.x-q.y*r.x-r.y*p.x;
double c3 = det(p,q,r);
Double3D a1 = new Double3D(a11,a21,a31);
Double3D a2 = new Double3D(a12,a22,a32);
Double3D a3 = new Double3D(a13,a23,a33);
Double3D c = new Double3D(c1,c2,c3);
return solveLinearEquation(a1,a2,a3,c);
}
/* center of circumsphere of tetrahedron pqrs
* when p,q,r,s are on a plane, return null
*/
public static Double3D centerOfCircumSphere(Double3D p,Double3D q,Double3D r,Double3D s){
double a11 = 2*(p.x-q.x);
double a12 = 2*(p.y-q.y);
double a13 = 2*(p.z-q.z);
double c1 = p.x*p.x+p.y*p.y+p.z*p.z-q.x*q.x-q.y*q.y-q.z*q.z;
double a21 = 2*(p.x-r.x);
double a22 = 2*(p.y-r.y);
double a23 = 2*(p.z-r.z);
double c2 = p.x*p.x+p.y*p.y+p.z*p.z-r.x*r.x-r.y*r.y-r.z*r.z;
double a31 = 2*(p.x-s.x);
double a32 = 2*(p.y-s.y);
double a33 = 2*(p.z-s.z);
double c3 = p.x*p.x+p.y*p.y+p.z*p.z-s.x*s.x-s.y*s.y-s.z*s.z;
Double3D a1 = new Double3D(a11,a21,a31);
Double3D a2 = new Double3D(a12,a22,a32);
Double3D a3 = new Double3D(a13,a23,a33);
Double3D c = new Double3D(c1,c2,c3);
return solveLinearEquation(a1,a2,a3,c);
}
public static Double3D midpoint(Double3D p,Double3D q){
return new Double3D((p.x+q.x)/2,(p.y+q.y)/2,(p.z+q.z)/2);
}
}
*高速Kruskal with 高速MFSet
O(NlogN)のMFsetを用いたKruskalのアルゴリズム.
class KruskalSolver{
int n;
double[][] dist;
double len;
private PriorityQueue<Edge> q;
KruskalSolver(int n,double dist[][]){
this.n = n;
this.dist = dist;
this.q = new PriorityQueue<Edge>();
this.len = 0.0;
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(dist[i][j]<Double.MAX_VALUE){
q.offer(new Edge(i, j, dist[i][j]));
}
}
}
//Kruskal's algorithm
MFSet mfs = new MFSet(n);
while(!q.isEmpty()){
Edge e = q.poll();
int i = e.p1;
int j = e.p2;
if(mfs.find(i)!=mfs.find(j)){
mfs.merge(mfs.find(i),mfs.find(j));
len += e.length;
}
}
}
}
class Edge implements Comparable<Edge>{
int p1;
int p2;
double length;
Edge(int i,int j,double l){
p1 = i;
p2 = j;
length = l;
}
public int compareTo(Edge e){
if(length>e.length) return 1;
else if(length==e.length) return 0;
else return -1;
}
}
class MFSet{
int n;
private int[] setsize;
private int[] firstelem;
private int[] set;
private int[] next;
MFSet(int n){
this.n = n;
setsize = new int[n];
Arrays.fill(setsize, 1);
firstelem = new int[n];
for(int i=0;i<n;i++) firstelem[i] = i;
set = new int[n];
for(int i=0;i<n;i++) set[i] = i;
next = new int[n];
for(int i=0;i<n;i++) next[i] = -1;
}
int find(int x){
return set[x];
}
void merge(int a, int b){
if(setsize[a]<setsize[b]){
merge(b, a);
return;
}
int i = firstelem[b];
while(next[i]>=0){
set[i] = a;
i = next[i];
}
set[i] = a;
next[i] = firstelem[a];
firstelem[a] = firstelem[b];
setsize[a] = setsize[a] + setsize[b];
setsize[b] = 0;
firstelem[b] = -1;
}
}
*Kruskal
O(N^2)のMFSetを用いたKruskalのアルゴリズム.
class KruskalSolver{
int n;
double[][] dist;
double len;
private PriorityQueue<Edge> q;
int[] set;
KruskalSolver(int n,double dist[][]){
this.n = n;
this.dist = dist;
this.len = 0.0;
this.q = new PriorityQueue<Edge>();
this.set = new int[n];
for(int i=0;i<n;i++) set[i] = i;
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(dist[i][j]<Double.MAX_VALUE){
q.offer(new Edge(i, j, dist[i][j]));
}
}
}
//Kruskal's algorithm
while(!q.isEmpty()){
Edge e = q.poll();
int i = e.p1;
int j = e.p2;
int si = set[i];
int sj = set[j];
if(si!=sj){
len += e.length;
for(int k=0;k<n;k++){
if(set[k]==sj) set[k] = si;
}
}
}
}
}
class Edge implements Comparable<Edge>{
int p1;
int p2;
double length;
Edge(int i,int j,double l){
p1 = i;
p2 = j;
length = l;
}
public int compareTo(Edge e){
if(length>e.length) return 1;
else if(length==e.length) return 0;
else return -1;
}
}
*Floyd
全点対間最短路.
class FloydSolver{
int n;
double[][] cost;
int[][] path;
FloydSolver(int n, double[][] dist) {
this.n = n;
cost = new double[n][n];
path = new int[n][n];
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cost[i][j] = dist[i][j];
path[i][j] = -1;
}
}
for(int k=0;k<n;k++){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(cost[i][k]==Double.MAX_VALUE ||
cost[k][j]==Double.MAX_VALUE) continue;
if(cost[i][k]+cost[k][j]<cost[i][j]){
cost[i][j] = cost[i][k] + cost[k][j];
path[i][j] = k;
}
}
}
}
}
public double pathLength(int v1, int v2){
return cost[v1][v2];
}
public ArrayList<Integer> path(int v1, int v2){
if(cost[v1][v2]==Double.MAX_VALUE) return null;
ArrayList<Integer> ret = new ArrayList<Integer>();
ret.add(v1);
path(v1, v2, ret);
ret.add(v2);
return ret;
}
private void path(int v1, int v2, ArrayList<Integer> ret){
int k = path[v1][v2];
if(k==-1) return;
else{
path(v1, k, ret);
ret.add(k);
path(k, v2, ret);
}
}
}
*平面幾何計算
class Double2D{
double x;
double y;
static final double EPS = 1.0E-9;
Double2D(double x,double y){
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object o){
Double2D p = (Double2D)o;
return x==p.x&&y==p.y;
}
public double squareDist(Double2D p){
return (x-p.x)*(x-p.x) + (y-p.y)*(y-p.y);
}
public double dist(Double2D p){
return Math.sqrt(this.squareDist(p));
}
// thisとpを通る半径rの円の中心
public Double2D[] centerOfPassingCircle1(Double2D p,double r){
if(this.dist(p)>r) return null; // 境界条件はテキトー
double a = p.x - x;
double b = p.y - y;
double d = this.dist(p);
double qx0 = x / 2 + p.x / 2 + Math.sqrt(r - d*d/4)*(-b)/d;
double qy0 = y / 2 + p.y / 2 + Math.sqrt(r - d*d/4)*a/d;
double qx1 = x / 2 + p.x / 2 - Math.sqrt(r - d*d/4)*(-b)/d;
double qy1 = y / 2 + p.y / 2 - Math.sqrt(r - d*d/4)*a/d;
Double2D[] ret = new Double2D[2];
ret[0] = new Double2D(qx0,qy0);
ret[1] = new Double2D(qx1,qy1);
return ret;
}
// 三点の作る三角形の面積
public static double squareOfTriangle(Double2D p1,Double2D p2,Double2D p3){
double x1 = p1.x-p2.x;
double x2 = p3.x-p2.x;
double y1 = p1.y-p2.y;
double y2 = p3.y-p2.y;
double s = (x1*y2-x2*y1)/2;
return Math.abs(s);
}
// 多角形の内部にあるかどうか 自己ループはないものとする
public static boolean inPolygon(ArrayList<Double2D> poly){
double acc = 0.0;
int n = poly.size();
for(int i=0;i<n-1;i++){
acc += arg(poly.get(i),poly.get(i+1));
}
acc += arg(poly.get(n-1),poly.get(0));
if(Math.abs(acc)<EPS) return false;
else return true;
}
// -Pi < theta < Pi の範囲で偏角を返す 複素数でいう Arg(p2/p1)
public static double arg(Double2D p1,Double2D p2){
double ax = p1.x;
double ay = p1.y;
double bx = p2.x;
double by = p2.y;
double theta = Math.atan2((ax*by-ay*bx)/(ax*ax+ay*ay),(ax*bx+ay*by)/(ax*ax+ay*ay));
return theta;
}
// 外接円の中心 Online Judge 検証なし 簡易検証あり
public static Double2D centerOfCircumscribingCircle(Double2D p1, Double2D p2, Double2D p3){
double x1 = p1.x, y1 = p1.y, x2 = p2.x, y2 = p2.y, x3 = p3.x, y3 = p3.y;
double det = (x1*(y2-y3)+x2*(y3-y1)+x3*(y1-y2));
if(Math.abs(det)<EPS) return null;
double sx =
-y1*(x2*x2+y2*y2-x3*x3-y3*y3)
-y2*(x3*x3+y3*y3-x1*x1-y1*y1)
-y3*(x1*x1+y1*y1-x2*x2-y2*y2);
double sy =
x1*(x2*x2+y2*y2-x3*x3-y3*y3)
+x2*(x3*x3+y3*y3-x1*x1-y1*y1)
+x3*(x1*x1+y1*y1-x2*x2-y2*y2);
return new Double2D(0.5*sx/det, 0.5*sy/det);
}
}
class Line{
double a;
double b;
double c;
static final double EPS = 1.0E-9;
Line(double a, double b, double c) {
this.a = a;
this.b = b;
this.c = c;
}
Line(Double2D p1,Double2D p2){
this.a = p1.y-p2.y;
this.b = -p1.x+p2.x;
this.c = -p1.x*(p1.y-p2.y)+p1.y*(p1.x-p2.x);
}
// 線分と線分の交点 ない場合は null
// 2線分が重なりをもつときは考えていない
public Double2D crossPoint(Line l){
// 平行
if(Math.abs(this.a*l.b-this.b*l.a)<EPS){
return null;
}
else{
double x = (-l.b*this.c+this.b*l.c)/(this.a*l.b-this.b*l.a);
double y = (l.a*this.c-this.a*l.c)/(this.a*l.b-this.b*l.a);
return new Double2D(x,y);
}
}
}
class Circle{
double x;
double y;
double r;
static final double EPS = 1.0E-9;
Circle(double x, double y, double r) {
this.x = x;
this.y = y;
this.r = r;
}
public double centerDist(Circle c){
return Math.sqrt((x-c.x)*(x-c.x)+(y-c.y)*(y-c.y));
}
// 2円の交点
public Double2D[] crossPoint1(Circle c){
double d = centerDist(c);
if(r+c.r > d) return null; // 境界条件はテキトー
double d1 = (d*d + r*r - c.r*c.r)/(2*d);
double ex = x + (c.x-x)*d1/d;
double ey = y + (c.y-y)*d1/d;
double l = Math.sqrt(r*r-d1*d1);
double lx = -(c.y-y)*l/d;
double ly = (c.x-x)*l/d;
Double2D[] ret = new Double2D[2];
ret[0] = new Double2D(ex+lx, ey+ly);
ret[1] = new Double2D(ex-lx, ey-ly);
return ret;
}
// 1点を通る接線
public Line[] tangentLine(Double2D p){
Line[] ret = new Line[2];
if(Math.abs((x-p.x)*(x-p.x)-r*r)<EPS){
ret[0] = new Line(1, 0, -p.x);
double m = ((y-p.y)*(y-p.y)-r*r)/(2*(x-p.x)*(y-p.y));
ret[1] = new Line(m, -1, -m*p.x+p.y);
}
else{
double m1 = ((x-p.x)*(y-p.y)+r*Math.sqrt((x-p.x)*(x-p.x)+(y-p.y)*(y-p.y)-r*r))/((x-p.x)*(x-p.x)-r*r);
double m2 = ((x-p.x)*(y-p.y)-r*Math.sqrt((x-p.x)*(x-p.x)+(y-p.y)*(y-p.y)-r*r))/((x-p.x)*(x-p.x)-r*r);
ret[0] = new Line(m1, -1, -m1*p.x+p.y);
ret[1] = new Line(m2, -1, -m2*p.x+p.y);
}
return ret;
}
}
class LineSegment{
Double2D p1;
Double2D p2;
static final double EPS = 1.0E-9;
LineSegment(double x1, double y1, double x2, double y2){
p1 = new Double2D(x1, y1);
p2 = new Double2D(x2, y2);
}
// 2線分が重なりをもつときは考えていない
public Double2D crossPoint(LineSegment ls){
Double2D p3 = ls.p1;
Double2D p4 = ls.p2;
if(fcompare(Math.max(p1.x, p2.x), Math.min(p3.x, p4.x))<0 ||
fcompare(Math.max(p3.x, p4.x), Math.min(p1.x, p2.x))<0 ||
fcompare(Math.max(p1.y, p2.y), Math.min(p3.y, p4.y))<0 ||
fcompare(Math.max(p3.y, p4.y), Math.min(p1.y, p2.y))<0) return null;
double dx00 = p2.x - p1.x;
double dy00 = p2.y - p1.y;
double dx01 = p3.x - p1.x;
double dy01 = p3.y - p1.y;
double dx02 = p4.x - p1.x;
double dy02 = p4.y - p1.y;
double dx10 = p4.x - p3.x;
double dy10 = p4.y - p3.y;
double dx11 = p1.x - p3.x;
double dy11 = p1.y - p3.y;
double dx12 = p2.x - p3.x;
double dy12 = p2.y - p3.y;
// 平行
if(Math.abs(dx00*dy10-dy00*dx10)<EPS){
if(p1.x==p3.x&&p1.y==p3.y) return p1;
if(p1.x==p4.x&&p1.y==p4.y) return p1;
if(p2.x==p3.x&&p2.y==p3.y) return p2;
if(p2.x==p4.x&&p2.y==p4.y) return p2;
}
if(fcompare((dx00*dy01-dx01*dy00)*(dx00*dy02-dx02*dy00), 0)<=0 &&
fcompare((dx10*dy11-dx11*dy10)*(dx10*dy12-dx12*dy10), 0)<=0){
Line l1 = new Line(p1, p2);
Line l2 = new Line(p3, p4);
return l1.crossPoint(l2);
}
else return null;
}
private int fcompare(double a, double b){
if(Math.abs(a-b)<EPS) return 0;
if(a>b) return 1;
else return -1;
}
}
*空間幾何計算
class Double3D{
double x;
double y;
double z;
Double3D(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public double dist(Double3D p){
double dx = p.x-this.x;
double dy = p.y-this.y;
double dz = p.z-this.z;
return Math.sqrt(dx*dx+dy*dy+dz*dz);
}
//determinant of matrix |a1 a2 a3| where a1,a2,a3 are column vectors
public static double det(Double3D a1,Double3D a2,Double3D a3){
double d1 = a1.x*(a2.y*a3.z-a2.z*a3.y);
double d2 = a1.y*(a2.x*a3.z-a2.z*a3.x);
double d3 = a1.z*(a2.x*a3.y-a2.y*a3.x);
return d1-d2+d3;
}
/* solution of linear equation
* where coefficient matrix is (a1 a2 a3) and c is constant vector
* when the solution is not unique, return null
*/
public static Double3D solveLinearEquation(Double3D a1,Double3D a2,Double3D a3,Double3D c){
double d = det(a1,a2,a3);
if(Math.abs(d)<1E-10) return null;
double o1 = det(c,a2,a3);
double o2 = det(a1,c,a3);
double o3 = det(a1,a2,c);
return new Double3D(o1/d,o2/d,o3/d);
}
/* center of circumcircle of Triangle pqr
* when p,q,r are on a line, return null
*/
public static Double3D centerOfCircumCircle(Double3D p,Double3D q,Double3D r){
double a11 = 2*(p.x-q.x);
double a12 = 2*(p.y-q.y);
double a13 = 2*(p.z-q.z);
double c1 = p.x*p.x+p.y*p.y+p.z*p.z-q.x*q.x-q.y*q.y-q.z*q.z;
double a21 = 2*(p.x-r.x);
double a22 = 2*(p.y-r.y);
double a23 = 2*(p.z-r.z);
double c2 = p.x*p.x+p.y*p.y+p.z*p.z-r.x*r.x-r.y*r.y-r.z*r.z;
double a31 = p.y*q.z+q.y*r.z+r.y*p.z-p.z*q.y-q.z*r.y-r.z*p.y;
double a32 = p.z*q.x+q.z*r.x+r.z*p.x-p.x*q.z-q.x*r.z-r.x*p.z;
double a33 = p.x*q.y+q.x*r.y+r.x*p.y-p.y*q.x-q.y*r.x-r.y*p.x;
double c3 = det(p,q,r);
Double3D a1 = new Double3D(a11,a21,a31);
Double3D a2 = new Double3D(a12,a22,a32);
Double3D a3 = new Double3D(a13,a23,a33);
Double3D c = new Double3D(c1,c2,c3);
return solveLinearEquation(a1,a2,a3,c);
}
/* center of circumsphere of tetrahedron pqrs
* when p,q,r,s are on a plane, return null
*/
public static Double3D centerOfCircumSphere(Double3D p,Double3D q,Double3D r,Double3D s){
double a11 = 2*(p.x-q.x);
double a12 = 2*(p.y-q.y);
double a13 = 2*(p.z-q.z);
double c1 = p.x*p.x+p.y*p.y+p.z*p.z-q.x*q.x-q.y*q.y-q.z*q.z;
double a21 = 2*(p.x-r.x);
double a22 = 2*(p.y-r.y);
double a23 = 2*(p.z-r.z);
double c2 = p.x*p.x+p.y*p.y+p.z*p.z-r.x*r.x-r.y*r.y-r.z*r.z;
double a31 = 2*(p.x-s.x);
double a32 = 2*(p.y-s.y);
double a33 = 2*(p.z-s.z);
double c3 = p.x*p.x+p.y*p.y+p.z*p.z-s.x*s.x-s.y*s.y-s.z*s.z;
Double3D a1 = new Double3D(a11,a21,a31);
Double3D a2 = new Double3D(a12,a22,a32);
Double3D a3 = new Double3D(a13,a23,a33);
Double3D c = new Double3D(c1,c2,c3);
return solveLinearEquation(a1,a2,a3,c);
}
public static Double3D midpoint(Double3D p,Double3D q){
return new Double3D((p.x+q.x)/2,(p.y+q.y)/2,(p.z+q.z)/2);
}
}
*高速Kruskal with 高速MFSet
O(NlogN)のMFsetを用いたKruskalのアルゴリズム.
class KruskalSolver{
int n;
double[][] dist;
double len;
private PriorityQueue<Edge> q;
KruskalSolver(int n,double dist[][]){
this.n = n;
this.dist = dist;
this.q = new PriorityQueue<Edge>();
this.len = 0.0;
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(dist[i][j]<Double.MAX_VALUE){
q.offer(new Edge(i, j, dist[i][j]));
}
}
}
//Kruskal's algorithm
MFSet mfs = new MFSet(n);
while(!q.isEmpty()){
Edge e = q.poll();
int i = e.p1;
int j = e.p2;
if(mfs.find(i)!=mfs.find(j)){
mfs.merge(mfs.find(i),mfs.find(j));
len += e.length;
}
}
}
}
class Edge implements Comparable<Edge>{
int p1;
int p2;
double length;
Edge(int i,int j,double l){
p1 = i;
p2 = j;
length = l;
}
public int compareTo(Edge e){
if(length>e.length) return 1;
else if(length==e.length) return 0;
else return -1;
}
}
class MFSet{
int n;
private int[] setsize;
private int[] firstelem;
private int[] set;
private int[] next;
MFSet(int n){
this.n = n;
setsize = new int[n];
Arrays.fill(setsize, 1);
firstelem = new int[n];
for(int i=0;i<n;i++) firstelem[i] = i;
set = new int[n];
for(int i=0;i<n;i++) set[i] = i;
next = new int[n];
for(int i=0;i<n;i++) next[i] = -1;
}
int find(int x){
return set[x];
}
void merge(int a, int b){
if(setsize[a]<setsize[b]){
merge(b, a);
return;
}
int i = firstelem[b];
while(next[i]>=0){
set[i] = a;
i = next[i];
}
set[i] = a;
next[i] = firstelem[a];
firstelem[a] = firstelem[b];
setsize[a] = setsize[a] + setsize[b];
setsize[b] = 0;
firstelem[b] = -1;
}
}
*Kruskal
O(N^2)のMFSetを用いたKruskalのアルゴリズム.
class KruskalSolver{
int n;
double[][] dist;
double len;
private PriorityQueue<Edge> q;
int[] set;
KruskalSolver(int n,double dist[][]){
this.n = n;
this.dist = dist;
this.len = 0.0;
this.q = new PriorityQueue<Edge>();
this.set = new int[n];
for(int i=0;i<n;i++) set[i] = i;
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(dist[i][j]<Double.MAX_VALUE){
q.offer(new Edge(i, j, dist[i][j]));
}
}
}
//Kruskal's algorithm
while(!q.isEmpty()){
Edge e = q.poll();
int i = e.p1;
int j = e.p2;
int si = set[i];
int sj = set[j];
if(si!=sj){
len += e.length;
for(int k=0;k<n;k++){
if(set[k]==sj) set[k] = si;
}
}
}
}
}
class Edge implements Comparable<Edge>{
int p1;
int p2;
double length;
Edge(int i,int j,double l){
p1 = i;
p2 = j;
length = l;
}
public int compareTo(Edge e){
if(length>e.length) return 1;
else if(length==e.length) return 0;
else return -1;
}
}
*Floyd
全点対間最短路.
class FloydSolver{
int n;
double[][] cost;
int[][] path;
FloydSolver(int n, double[][] dist) {
this.n = n;
cost = new double[n][n];
path = new int[n][n];
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cost[i][j] = dist[i][j];
path[i][j] = -1;
}
}
for(int k=0;k<n;k++){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(cost[i][k]==Double.MAX_VALUE ||
cost[k][j]==Double.MAX_VALUE) continue;
if(cost[i][k]+cost[k][j]<cost[i][j]){
cost[i][j] = cost[i][k] + cost[k][j];
path[i][j] = k;
}
}
}
}
}
public double pathLength(int v1, int v2){
return cost[v1][v2];
}
public ArrayList<Integer> path(int v1, int v2){
if(cost[v1][v2]==Double.MAX_VALUE) return null;
ArrayList<Integer> ret = new ArrayList<Integer>();
ret.add(v1);
path(v1, v2, ret);
ret.add(v2);
return ret;
}
private void path(int v1, int v2, ArrayList<Integer> ret){
int k = path[v1][v2];
if(k==-1) return;
else{
path(v1, k, ret);
ret.add(k);
path(k, v2, ret);
}
}
}
*最大流問題
class MaxFlowSolver {
int size;//number of nodes
int source;//nodeID of source
int sink;//nodeID of sink
int[][] network;
int[] prev;
MaxFlowSolver(int n, int s, int t, int[][] net) {
size = n;
source = s;
sink = t;
network = net;
prev = new int[size];
}
public int solve() {
int flow = 0;
while (searchPath()) {
int flowinc = Integer.MAX_VALUE;
// calculate how much flow increases
int v = sink;
while (prev[v]<Integer.MAX_VALUE) {
flowinc = Math.min(flowinc, network[prev[v]][v]);
v = prev[v];
}
//flow increases
flow += flowinc;
//update network array
v = sink;
while(prev[v]<Integer.MAX_VALUE){
network[prev[v]][v] -= flowinc;
network[v][prev[v]] += flowinc;
v = prev[v];
}
}
return flow;
}
//search shortest path from source to sink by BFS
private boolean searchPath() {
Arrays.fill(prev, -1);
Queue<Integer> q = new LinkedList<Integer>();
q.offer(source);
prev[source] = Integer.MAX_VALUE;
L: while (!q.isEmpty()) {
int u = q.poll();
for (int i = 0; i < size; i++) {
if (prev[i] < 0 && network[u][i] > 0) {
prev[i] = u;
//discoverd path to sink
if (i == sink) break L;
q.offer(i);
}
}
}
return prev[sink]>=0;
}
}
表示オプション
横に並べて表示:
変化行の前後のみ表示: