I followed the algorithm mentioned in the sig09 paper Coordinates for Instant Image Cloning
The algorithm
This is my code:
#include<iostream>
#include<vector>
#include<map>
#include<fstream>
#include<queue>
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include"../shared/stb_image.h"
#include"../shared/stb_image_write.h"
#define vector std::vector
#define queue std::queue
#define map std::map
#define cin std::cin
#define cout std::cout
#define endl std::endl
#define string std::string
#define PDD std::pair<double, double>
#define image Mat<unsigned char>
template<class T>
class Mat{
public:
int row, col, channel;
vector<T> data;
Mat(){}
Mat(int row, int col, int cha):row(row), col(col), channel(cha){
data.resize(row * col * cha, 0);
}
Mat(const char *name){
T *t = stbi_load(name, &col, &row, &channel, 0);
data = vector<T>(t, t + col * row * channel);
stbi_image_free(t);
}
T& at(int x, int y, int z){
return data[(x * col + y) * channel + z];
}
void write(const char *name){
stbi_write_bmp(name, col, row, channel, data.data());
}
};
#define x first
#define y second
vector<PDD> P;
map<int, map<int, bool>> st; // register
vector<vector<double>> w;
int dx8[] = {1, 1, 1, 0, 0, -1, -1, -1}, dy8[] = {-1, 0, 1, -1, 1, -1, 0, 1};
int dx4[] = {0, 0, 1, -1}, dy4[] = {1, -1, 0, 0};
bool check(int i, int j, image &mask){
if(mask.at(i, j, 0) == 0) return false;
return mask.at(i, j - 1, 0) == 0||
mask.at(i, j + 1, 0) == 0||
mask.at(i - 1, j, 0) == 0||
mask.at(i + 1, j, 0) == 0;
}
void dfs(int sx, int sy, int x, int y, int px, int py, image &mask){
if(mask.at(x, y - 1, 0) == 0 && st[x][y - 1] == 0) P.push_back({x, y - 1}), st[x][y - 1] = 1;
if(px != -1){
if(mask.at(x + 1, y, 0) == 0 && st[x + 1][y] == 0) P.push_back({x + 1, y}), st[x + 1][y] = 1;
if(mask.at(x, y + 1, 0) == 0 && st[x][y + 1] == 0) P.push_back({x, y + 1}), st[x][y + 1] = 1;
if(mask.at(x - 1, y, 0) == 0 && st[x - 1][y] == 0) P.push_back({x - 1, y}), st[x - 1][y] = 1;
}
if(sx == x && sy == y && px != -1) return;
for(int i = 0; i < 8; i ++){
int a = x + dx8[i], b = y + dy8[i];
if(a < 0 || b < 0 || a >= mask.row || b >= mask.col) continue;
if(check(a, b, mask) && (a != px || b != py)) dfs(sx, sy, a, b, x, y, mask);
}
}
double len(const PDD &a){
return sqrt(a.x * a.x + a.y * a.y);
}
double dot(const PDD &a, const PDD &b){
return a.x * b.x + a.y * b.y;
}
PDD minus(const PDD &a, const PDD &b){
return {a.x - b.x, a.y - b.y};
}
PDD normalize(const PDD &a){
return {a.x / len(a), a.y / len(a)};
}
double val(PDD &pre, PDD &cur, PDD &nxt, PDD &o){
PDD V1 = normalize(minus(pre, o));
PDD V2 = normalize(minus(nxt, o));
PDD mid = normalize(minus(cur, o));
double alpha1 = acos(dot(V1, mid));
double alpha2 = acos(dot(V2, mid));
return (tan(alpha1 / 2) + tan(alpha2 / 2)) / len(minus(cur, o)); // many nan value occured here
}
int main(int argc, char *argv[]){
image src("src.png");
image mask("mask1.png");
image tar("target.png");
image res(tar.row, tar.col, tar.channel);
for(int i = 0; i < mask.row; i ++){
for(int j = 0; j < mask.col; j ++){
if(mask.at(i, j, 0) == 255 && st[i][j] == 0){
dfs(i, j, i, j, -1, -1, mask); // find counter-clockwise border
queue<PDD> q;
vector<PDD> X;
q.push({i, j});
st[i][j] = 1;
while(q.size()){ // get all white (x, y)s in mask
auto h = q.front();
X.push_back(h);
q.pop();
vector<double> wx;
for(int k = 0; k < P.size(); k ++){ // calculate lambda value by search order
int pre = (k - 1 + P.size()) % P.size();
int cur = k;
int nxt = (k + 1) % P.size();
wx.push_back(
val(P[pre], P[cur], P[nxt], h)
);
}
w.push_back(wx);
for(int k = 0; k < 4; k ++){
int a = h.x + dx4[k], b = h.y + dy4[k];
if(st[a][b] == 1 || mask.at(a, b, 0) == 0) continue;
st[a][b] = 1;
q.push({a, b});
}
}
for(int c = 0; c < res.channel; c ++){ // every channel of res
for(int k = 0; k < X.size(); k ++){
double rx = 0, sum = 0;
for(int u = 0; u < w[k].size(); u ++){
double diff = tar.at(P[u].x, P[u].y, c) - src.at(P[u].x, P[u].y, c);
rx += w[k][u] * diff;
sum += w[k][u];
}
rx /= sum;
res.at(X[k].x, X[k].y, c) = rx + src.at(X[k].x, X[k].y, c);
}
}
res.write("./res.bmp");
return 0;
}
}
}
}
1. get the border(counter-clockwise) of the white region in the
mask
2. get all (x, y)s of pixels in the white area of the mask
3. calculate lambda value of every (x, y) in 2, but I found that lambda values of every (x, y) contain many nans (possibly caused by too small value in function val(...))
The question is I do not know how to deal with this condition in 3, nor did the paper mention it.
Related
I search for non iterative, closed form, algorithm to find Least squares solution for point closest to the set of 3d lines. It is similar to 3d point triangulation (to minimize re-projections) but seems to be be simpler and faster?
Lines can be described in any form, 2 points, point and unit direction or similar.
Let the i th line be given by point ai and unit direction vector di. We need to find the single point that minimizes the sum of squared point to line distances. This is where the gradient is the zero vector:
Expanding the gradient,
Algebra yields a canonical 3x3 linear system,
where the k'th row (a 3-element row vector) of matrix M is
with vector ek the respective unit basis vector, and
It's not hard to turn this into code. I borrowed (and fixed a small bug in) a Gaussian elimination function from Rosettacode to solve the system. Thanks to the author!
#include <stdio.h>
#include <math.h>
typedef double VEC[3];
typedef VEC MAT[3];
void solve(double *a, double *b, double *x, int n); // linear solver
double dot(VEC a, VEC b) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; }
void find_nearest_point(VEC p, VEC a[], VEC d[], int n) {
MAT m = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
VEC b = {0, 0, 0};
for (int i = 0; i < n; ++i) {
double d2 = dot(d[i], d[i]), da = dot(d[i], a[i]);
for (int ii = 0; ii < 3; ++ii) {
for (int jj = 0; jj < 3; ++jj) m[ii][jj] += d[i][ii] * d[i][jj];
m[ii][ii] -= d2;
b[ii] += d[i][ii] * da - a[i][ii] * d2;
}
}
solve(&m[0][0], b, p, 3);
}
// Debug printing.
void pp(VEC v, char *l, char *r) {
printf("%s%.3lf, %.3lf, %.3lf%s", l, v[0], v[1], v[2], r);
}
void pv(VEC v) { pp(v, "(", ")"); }
void pm(MAT m) { for (int i = 0; i < 3; ++i) pp(m[i], "\n[", "]"); }
// A simple verifier.
double dist2(VEC p, VEC a, VEC d) {
VEC pa = { a[0]-p[0], a[1]-p[1], a[2]-p[2] };
double dpa = dot(d, pa);
return dot(d, d) * dot(pa, pa) - dpa * dpa;
}
double sum_dist2(VEC p, VEC a[], VEC d[], int n) {
double sum = 0;
for (int i = 0; i < n; ++i) sum += dist2(p, a[i], d[i]);
return sum;
}
// Check 26 nearby points and verify the provided one is nearest.
int is_nearest(VEC p, VEC a[], VEC d[], int n) {
double min_d2 = 1e100;
int ii = 2, jj = 2, kk = 2;
#define D 0.01
for (int i = -1; i <= 1; ++i)
for (int j = -1; j <= 1; ++j)
for (int k = -1; k <= 1; ++k) {
VEC pp = { p[0] + D * i, p[1] + D * j, p[2] + D * k };
double d2 = sum_dist2(pp, a, d, n);
// Prefer provided point among equals.
if (d2 < min_d2 || i == 0 && j == 0 && k == 0 && d2 == min_d2) {
min_d2 = d2;
ii = i; jj = j; kk = k;
}
}
return ii == 0 && jj == 0 && kk == 0;
}
void normalize(VEC v) {
double len = sqrt(dot(v, v));
v[0] /= len;
v[1] /= len;
v[2] /= len;
}
int main(void) {
VEC a[] = {{-14.2, 17, -1}, {1, 1, 1}, {2.3, 4.1, 9.8}, {1,2,3}};
VEC d[] = {{1.3, 1.3, -10}, {12.1, -17.2, 1.1}, {19.2, 31.8, 3.5}, {4,5,6}};
int n = 4;
for (int i = 0; i < n; ++i) normalize(d[i]);
VEC p;
find_nearest_point(p, a, d, n);
pv(p);
printf("\n");
if (!is_nearest(p, a, d, n)) printf("Woops. Not nearest.\n");
return 0;
}
// A linear solver from rosettacode (with bug fix: added a missing fabs())
#define mat_elem(a, y, x, n) (a + ((y) * (n) + (x)))
void swap_row(double *a, double *b, int r1, int r2, int n)
{
double tmp, *p1, *p2;
int i;
if (r1 == r2) return;
for (i = 0; i < n; i++) {
p1 = mat_elem(a, r1, i, n);
p2 = mat_elem(a, r2, i, n);
tmp = *p1, *p1 = *p2, *p2 = tmp;
}
tmp = b[r1], b[r1] = b[r2], b[r2] = tmp;
}
void solve(double *a, double *b, double *x, int n)
{
#define A(y, x) (*mat_elem(a, y, x, n))
int i, j, col, row, max_row, dia;
double max, tmp;
for (dia = 0; dia < n; dia++) {
max_row = dia, max = fabs(A(dia, dia));
for (row = dia + 1; row < n; row++)
if ((tmp = fabs(A(row, dia))) > max) max_row = row, max = tmp;
swap_row(a, b, dia, max_row, n);
for (row = dia + 1; row < n; row++) {
tmp = A(row, dia) / A(dia, dia);
for (col = dia+1; col < n; col++)
A(row, col) -= tmp * A(dia, col);
A(row, dia) = 0;
b[row] -= tmp * b[dia];
}
}
for (row = n - 1; row >= 0; row--) {
tmp = b[row];
for (j = n - 1; j > row; j--) tmp -= x[j] * A(row, j);
x[row] = tmp / A(row, row);
}
#undef A
}
This isn't extensively tested, but seems to be working fine.
Let base point of line is p and unit direction vector is d.
Then distance from point v to this line might be calculated using cross product
SquaredDist = ((v - p) x d)^2
Using Maple packet symbolic calculation, we can get
d := <dx, dy, dz>;
v := <vx, vy, vz>;
p := <px, py, pz>;
w := v - p;
cp := CrossProduct(d, w);
nrm := BilinearForm(cp, cp, conjugate=false); //squared dist
nr := expand(nrm);
//now partial derivatives
nrx := diff(nr, vx);
//results:
nrx := -2*dz^2*px-2*dy^2*px+2*dz^2*vx+2*dy^2*vx
+2*dx*py*dy-2*dx*vy*dy+2*dz*dx*pz-2*dz*dx*vz
nry := -2*dx^2*py-2*dz^2*py-2*dy*vz*dz+2*dx^2*vy
+2*dz^2*vy+2*dy*pz*dz+2*dx*dy*px-2*dx*dy*vx
nrz := -2*dy^2*pz+2*dy^2*vz-2*dy*dz*vy+2*dx^2*vz
-2*dx^2*pz-2*dz*vx*dx+2*dy*dz*py+2*dz*px*dx
To minimize sum of squared distances, we have to make system of linear equations for zero partial derivatives like this:
vx*2*(Sum(dz^2)+Sum(dy^2)) + vy * (-2*Sum(dx*dy)) + vz *(-2*Sum(dz*dx)) =
2*Sum(dz^2*px)-2*Sum(dy^2*px) -2*Sum(dx*py*dy)-2*Sum(dz*dx*pz)
where
Sum(dz^2) = Sum{over all i in line indexes} {dz[i] * dz[i]}
and solve it for unknowns vx, vy, vz
Edit: Old erroneous answer for planes instead of lines, left for reference
If we use general equation of line
A * x + B * y + C * z + D = 0
then distance from point (x, y, z) to this line is
Dist = Abs(A * x + B * y + C * z + D) / Sqrt(A^2 + B^2 + C^2)
To simplify - just normalize all line equations dividing by Norm's
Norm = Sqrt(A^2 + B^2 + C^2)
a = A / Norm
b = B / Norm
c = C / Norm
d = D / Norm
now equation is
a * x + b * y + c * z + d = 0
and distance
Dist = Abs(a * x + b * y + c * z + d)
and we can use squared distances like LS method (ai, bi, ci, di are coefficients for i-th line)
F = Sum(ai*x + bi*y + ci * z + d)^2 =
Sum(ai^2*x^2 + bi^2*y^2 + ci^2*z^2 + d^2 +
2 * (ai*bi*x*y + ai*ci*x*z + bi*y*ci*z + ai*x*di + bi*y*di + ci*z*di))
partial derivatives
dF/dx = 2*Sum(ai^2*x + ai*bi*y + ai*ci*z + ai*di) = 0
dF/dy = 2*Sum(bi^2*y + ai*bi*x + bi*ci*z + bi*di) = 0
dF/dz = 2*Sum(ci^2*z + ai*ci*x + bi*ci*y + ci*di) = 0
so we have system of linear equation
x * Sum(ai^2) + y * Sum(ai*bi) + z * Sum(ai*ci)= - Sum(ai*di)
y * Sum(bi^2) + x * Sum(ai*bi) + z * Sum(bi*ci)= - Sum(bi*di)
z * Sum(ci^2) + x * Sum(ai*ci) + y * Sum(bi*ci)= - Sum(ci*di)
x * Saa + y * Sab + z * Sac = - Sad
x * Sab + y * Sbb + z * Sbc = - Sbd
x * Sac + y * Sbc + z * Scc = - Scd
where S** are corresponding sums
and can solve it for unknowns x, y, z
I needed this for a sketch in Processing, so I ported Gene's answer. Works great and thought it might save someone else a little time. Unfortunately PVector/PMatrix don't have array accessors for vectors or matrices so I had to add these as local functions.
float getv(PVector v, int i) {
if(i == 0) return v.x;
if(i == 1) return v.y;
return v.z;
}
void setv(PVector v, int i, float value) {
if (i == 0) v.x = value;
else if (i == 1) v.y = value;
else v.z = value;
}
void incv(PVector v, int i, float value) {
setv(v,i,getv(v,i) + value);
}
float getm(float[] mm, int r, int c) { return mm[c + r*4]; }
void setm(float[] mm, int r, int c, float value) { mm[c + r*4] = value; }
void incm(float[] mm, int r, int c, float value) { mm[c + r*4] += value; }
PVector findNearestPoint(PVector a[], PVector d[]) {
var mm = new float[16];
var b = new PVector();
var n = a.length;
for (int i = 0; i < n; ++i) {
var d2 = d[i].dot(d[i]);
var da = d[i].dot(a[i]);
for (int ii = 0; ii < 3; ++ii) {
for (int jj = 0; jj < 3; ++jj) {
incm(mm,ii,jj, getv(d[i],ii) * getv(d[i],jj));
}
incm(mm, ii,ii, -d2);
incv(b, ii, getv(d[i], ii) * da - getv(a[i], ii) * d2);
}
}
var p = solve(mm, new float[] {b.x, b.y, b.z});
return new PVector(p[0],p[1],p[2]);
}
// Verifier
float dist2(PVector p, PVector a, PVector d) {
PVector pa = new PVector( a.x-p.x, a.y-p.y, a.z-p.z );
float dpa = d.dot(pa);
return d.dot(d) * pa.dot(pa) - dpa * dpa;
}
//double sum_dist2(VEC p, VEC a[], VEC d[], int n) {
float sum_dist2(PVector p, PVector a[], PVector d[]) {
int n = a.length;
float sum = 0;
for (int i = 0; i < n; ++i) {
sum += dist2(p, a[i], d[i]);
}
return sum;
}
// Check 26 nearby points and verify the provided one is nearest.
boolean isNearest(PVector p, PVector a[], PVector d[]) {
float min_d2 = 3.4028235E38;
int ii = 2, jj = 2, kk = 2;
final float D = 0.1f;
for (int i = -1; i <= 1; ++i)
for (int j = -1; j <= 1; ++j)
for (int k = -1; k <= 1; ++k) {
PVector pp = new PVector( p.x + D * i, p.y + D * j, p.z + D * k );
float d2 = sum_dist2(pp, a, d);
// Prefer provided point among equals.
if (d2 < min_d2 || i == 0 && j == 0 && k == 0 && d2 == min_d2) {
min_d2 = d2;
ii = i; jj = j; kk = k;
}
}
return ii == 0 && jj == 0 && kk == 0;
}
void setup() {
PVector a[] = {
new PVector(-14.2, 17, -1),
new PVector(1, 1, 1),
new PVector(2.3, 4.1, 9.8),
new PVector(1,2,3)
};
PVector d[] = {
new PVector(1.3, 1.3, -10),
new PVector(12.1, -17.2, 1.1),
new PVector(19.2, 31.8, 3.5),
new PVector(4,5,6)
};
int n = 4;
for (int i = 0; i < n; ++i)
d[i].normalize();
PVector p = findNearestPoint(a, d);
println(p);
if (!isNearest(p, a, d))
println("Woops. Not nearest.\n");
}
// From rosettacode (with bug fix: added a missing fabs())
int mat_elem(int y, int x) { return y*4+x; }
void swap_row(float[] a, float[] b, int r1, int r2, int n)
{
float tmp;
int p1, p2;
int i;
if (r1 == r2) return;
for (i = 0; i < n; i++) {
p1 = mat_elem(r1, i);
p2 = mat_elem(r2, i);
tmp = a[p1];
a[p1] = a[p2];
a[p2] = tmp;
}
tmp = b[r1];
b[r1] = b[r2];
b[r2] = tmp;
}
float[] solve(float[] a, float[] b)
{
float[] x = new float[] {0,0,0};
int n = x.length;
int i, j, col, row, max_row, dia;
float max, tmp;
for (dia = 0; dia < n; dia++) {
max_row = dia;
max = abs(getm(a, dia, dia));
for (row = dia + 1; row < n; row++) {
if ((tmp = abs(getm(a, row, dia))) > max) {
max_row = row;
max = tmp;
}
}
swap_row(a, b, dia, max_row, n);
for (row = dia + 1; row < n; row++) {
tmp = getm(a, row, dia) / getm(a, dia, dia);
for (col = dia+1; col < n; col++) {
incm(a, row, col, -tmp * getm(a, dia, col));
}
setm(a,row,dia, 0);
b[row] -= tmp * b[dia];
}
}
for (row = n - 1; row >= 0; row--) {
tmp = b[row];
for (j = n - 1; j > row; j--) {
tmp -= x[j] * getm(a, row, j);
}
x[row] = tmp / getm(a, row, row);
}
return x;
}
You are given a matrix of order (M x N). You can move in 4 directions: left, top, right and bottom. You are given initial position (x, y) and number of steps which you can move from the given location. While moving if you go out of the matrix, you are disqualified from the game. What is the probability that you are not disqualified?
I solved the question in the following two ways:
Way 1. Find out total ways say T1 in which you will be inside the matrix and find out total ways T2 in which you will be out of the matrix. Then return T1 / (T1 + T2) as the result.
Way 2. Use the fact that probability of reaching your neighbor is: 1/4 as you can move only in 4 directions from the given position and calculate the result.
But the two approaches are giving different results in many scenarios.
Please find my code below and do let me know where I am mistaken or if there is fault in the approaches.
public class ProbabilityOfStay {
private int[] x = {0, 1, 0, -1};
private int[] y = {-1, 0, 1, 0};
private int ROW;
private int COL;
private int xPos;
private int yPos;
private int steps ;
int[][][] stayDP = null;
int[][][] nonStayDP = null;
float[][][] sp = null;
public ProbabilityOfStay(int R, int C, int x, int y, int steps)
{
this.ROW = R;
this.COL = C;
this.xPos = x;
this.yPos = y;
this.steps = steps;
stayDP = new int[ROW][COL][steps];
nonStayDP = new int[ROW][COL][steps];
sp = new float[ROW][COL][steps];
this.initializeInt(stayDP, -1);
this.initializeInt(nonStayDP, -1);
this.initializeF(sp, -1);
}
private void initializeInt(int[][][] M, int d)
{
for(int i = 0; i < ROW; i++)
{
for(int j = 0; j < COL; j++)
{
for(int k = 0; k < steps; k++)
M[i][j][k] = d;
}
}
}
private void initializeF(float[][][] M, int d)
{
for(int i = 0; i < ROW; i++)
{
for(int j = 0; j < COL; j++)
{
for(int k = 0; k < steps; k++)
M[i][j][k] = d;
}
}
}
private int getTotalStayPath()
{
int p = getStayPaths(xPos, yPos, steps);
return p;
}
private int getStayPaths(int xp, int yp, int s)
{
if(xp < 0 || xp >= ROW || yp < 0 || yp >= COL)
return 0;
if(s == 0)
return 1;
if(stayDP[xp][yp][s-1] != -1)
return stayDP[xp][yp][s-1];
int ans = 0;
for(int i = 0; i < x.length; i++)
{
ans += getStayPaths(xp + x[i], yp + y[i], s-1);
}
return (stayDP[xp][yp][s-1] = ans);
}
private int getTotalNonStayPath()
{
int p = getNonStayPaths(xPos, yPos, steps);
return p;
}
private int getNonStayPaths(int xp, int yp, int s)
{
if(xp < 0 || xp >= ROW || yp < 0 || yp >= COL)
return 1;
if(s == 0)
return 0;
if(nonStayDP[xp][yp][s-1] != -1)
return nonStayDP[xp][yp][s-1];
int ans = 0;
for(int i = 0; i < x.length; i++)
{
ans += getNonStayPaths(xp + x[i], yp + y[i], s - 1);
}
return (nonStayDP[xp][yp][s-1] = ans);
}
private float getStayProbabilityM()
{
float p = getProbability(xPos, yPos, steps);
return p;
}
private float getProbability(int xp, int yp, int s)
{
if(xp < 0 || xp >= ROW || yp < 0 || yp >= COL)
return 0;
if(s == 0)
return 1;
if(sp[xp][yp][s-1] != -1)
return sp[xp][yp][s-1];
float ans = 0.0f;
for(int i = 0; i < x.length; i++)
{
ans += (getProbability(xp + x[i], yp + y[i], s-1)) / 4.0;
}
return (sp[xp][yp][s-1] = ans);
}
public static void main(String[] args)
{
int ROW = 7, COL = 7, x = 3, y = 5, steps = 3; //(x, y) is your position in the matrix.
ProbabilityOfStay pos = new ProbabilityOfStay(ROW, COL, x, y, steps);
int totalStayPaths = pos.getTotalStayPath(); //number of ways in which you can stay in the matrix.
int totalNonStayPaths = pos.getTotalNonStayPath(); ////number of ways in which you can't stay in the matrix.
float stayingProbability = (totalStayPaths / (float)(totalStayPaths + totalNonStayPaths));
float sP_memorization = pos.getStayProbabilityM();
System.out.println("Total stay paths: " + totalStayPaths + ", total non-stay paths: " + totalNonStayPaths + ", Stay probability: " + stayingProbability);
System.out.println("Total probability memoriation: " + sP_memorization);
}
}
If I run the program it prints:
Total stay paths: 56, total non-stay paths: 5
However, this results in a total number of paths of 56+5=61.
There are 4 choices at each of 3 steps, so the total should be 4*4*4 = 64.
I think the issue is that you stop counting as soon as the path goes off the board. This means that the paths are not of equal probability so your calculation by dividing the number of paths is not valid.
If you change the computation to:
float stayingProbability = (totalStayPaths / (float)Math.pow(4,steps));
it prints matching answers.
I am using Sutherland Hodgman's Algorithm inorder to clip the polygon overlay for clipping Spatial Query. And I want to implement erase overlay function as well. So suggest me some algorithm like Sutherland Hodgman Algorithm or Can anyone modify this Sutherland Hodgman Algorithm for me.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct { double x, y; } vec_t, *vec;
inline double dot(vec a, vec b)
{
return a->x * b->x + a->y * b->y;
}
inline double cross(vec a, vec b)
{
return a->x * b->y - a->y * b->x;
}
inline vec vsub(vec a, vec b, vec res)
{
res->x = a->x - b->x;
res->y = a->y - b->y;
return res;
}
/* tells if vec c lies on the left side of directed edge a->b
* 1 if left, -1 if right, 0 if colinear
*/
int left_of(vec a, vec b, vec c)
{
vec_t tmp1, tmp2;
double x;
vsub(b, a, &tmp1);
vsub(c, b, &tmp2);
x = cross(&tmp1, &tmp2);
return x < 0 ? -1 : x > 0;
}
int line_sect(vec x0, vec x1, vec y0, vec y1, vec res)
{
vec_t dx, dy, d;
vsub(x1, x0, &dx);
vsub(y1, y0, &dy);
vsub(x0, y0, &d);
/* x0 + a dx = y0 + b dy ->
x0 X dx = y0 X dx + b dy X dx ->
b = (x0 - y0) X dx / (dy X dx) */
double dyx = cross(&dy, &dx);
if (!dyx) return 0;
dyx = cross(&d, &dx) / dyx;
if (dyx <= 0 || dyx >= 1) return 0;
res->x = y0->x + dyx * dy.x;
res->y = y0->y + dyx * dy.y;
return 1;
}
/* === polygon stuff === */
typedef struct { int len, alloc; vec v; } poly_t, *poly;
poly poly_new()
{
poly p = (poly)malloc(sizeof(poly_t));
p->len = p->alloc = 0;
p->v = 0;
return p;
}
void poly_free(poly p)
{
if (p->alloc) {
free(p->v);
free(p);
}
}
void poly_append(poly p, vec v)
{
if (p->len >= p->alloc) {
p->alloc *= 2;
if (!p->alloc) p->alloc = 4;
p->v = (vec)realloc(p->v, sizeof(vec_t) * p->alloc);
}
p->v[p->len++] = *v;
}
/* this works only if all of the following are true:
* 1. poly has no colinear edges;
* 2. poly has no duplicate vertices;
* 3. poly has at least three vertices;
* 4. poly is convex (implying 3).
*/
int poly_winding(poly p)
{
return left_of(&p->v[0], &p->v[1], &p->v[2]);
}
void poly_edge_clip(poly sub, vec x0, vec x1, int left, poly res)
{
int i, side0, side1;
vec_t tmp;
vec v0 = &sub->v[sub->len - 1], v1;
res->len = 0;
side0 = left_of(x0, x1, v0);
if (side0 != -left) poly_append(res, v0);
for (i = 0; i < sub->len; i++) {
v1 = &sub->v[i];
side1 = left_of(x0, x1, v1);
if (side0 + side1 == 0 && side0)
/* last point and current straddle the edge */
if (line_sect(x0, x1, v0, v1, &tmp))
poly_append(res, &tmp);
if (i == sub->len - 1) break;
if (side1 != -left) poly_append(res, v1);
v0 = v1;
side0 = side1;
}
}
poly poly_clip(poly sub, poly clip)
{
int i;
poly p1 = poly_new(), p2 = poly_new(), tmp;
int dir = poly_winding(clip);
poly_edge_clip(sub, &clip->v[clip->len - 1], &clip->v[0], dir, p2);
for (i = 0; i < clip->len - 1; i++) {
tmp = p2; p2 = p1; p1 = tmp;
poly_edge_clip(p1, &clip->v[i], &clip->v[i + 1], dir, p2);
}
poly_free(p1);
return p2;
}
int main()
{
int i;
vec_t c[] = {{200,200}, {400,200}, {400,400}, {200,400}};
//vec_t c[] = {{100,300}, {300,300}, {300,100}, {100,100}};
vec_t s[] = { {50,150}, {200,50}, {350,150},
{350,300},{250,300},{200,250},
{150,350},{100,250},{100,200}};
#define clen (sizeof(c)/sizeof(vec_t))
#define slen (sizeof(s)/sizeof(vec_t))
poly_t clipper = {clen, 0, c};
poly_t subject = {slen, 0, s};
poly res = poly_clip(&subject, &clipper);
for (i = 0; i < res->len; i++)
printf("%g %g\n", res->v[i].x, res->v[i].y);
/* long and arduous EPS printout */
FILE * eps = fopen("test.eps", "w");
fprintf(eps, "%%!PS-Adobe-3.0\n%%%%BoundingBox: 40 40 360 360\n"
"/l {lineto} def /m{moveto} def /s{setrgbcolor} def"
"/c {closepath} def /gs {fill grestore stroke} def\n");
fprintf(eps, "0 setlinewidth %g %g m ", c[0].x, c[0].y);
for (i = 1; i < clen; i++)
fprintf(eps, "%g %g l ", c[i].x, c[i].y);
fprintf(eps, "c .5 0 0 s gsave 1 .7 .7 s gs\n");
fprintf(eps, "%g %g m ", s[0].x, s[0].y);
for (i = 1; i < slen; i++)
fprintf(eps, "%g %g l ", s[i].x, s[i].y);
fprintf(eps, "c 0 .2 .5 s gsave .4 .7 1 s gs\n");
fprintf(eps, "2 setlinewidth [10 8] 0 setdash %g %g m ",
res->v[0].x, res->v[0].y);
for (i = 1; i < res->len; i++)
fprintf(eps, "%g %g l ", res->v[i].x, res->v[i].y);
fprintf(eps, "c .5 0 .5 s gsave .7 .3 .8 s gs\n");
fprintf(eps, "%%%%EOF");
fclose(eps);
printf("test.eps written\n");
return 0;
}
In the draft section 7.2.1.3 of The art of computer programming, generating all combinations, Knuth introduced Algorithm C for generating Chase's sequence.
He also mentioned a similar algorithm (based on the following equation) working with index-list without source code (exercise 45 of the draft).
I finally worked out a c++ version which I think is quite ugly. To generate all C_n^m combination, the memory complexity is about 3 (m+1) and the time complexity is bounded by O(m n^m)
class chase_generator_t{
public:
using size_type = ptrdiff_t;
enum class GET : char{ VALUE, INDEX };
chase_generator_t(size_type _n) : n(_n){}
void choose(size_type _m){
m = _m;
++_m;
index.resize(_m);
threshold.resize(_m + 1);
tag.resize(_m);
for (size_type i = 0, j = n - m; i != _m; ++i){
index[i] = j + i;
tag[i] = tag_t::DECREASE;
using std::max;
threshold[i] = max(i - 1, (index[i] - 3) | 1);
}
threshold[_m] = n;
}
bool get(size_type &x, size_type &y, GET const which){
if (which == GET::VALUE) return __get<false>(x, y);
return __get<true>(x, y);
}
size_type get_n() const{
return n;
}
size_type get_m() const{
return m;
}
size_type operator[](size_t const i) const{
return index[i];
}
private:
enum class tag_t : char{ DECREASE, INCREASE };
size_type n, m;
std::vector<size_type> index, threshold;
std::vector<tag_t> tag;
template<bool GetIndex>
bool __get(size_type &x, size_type &y){
using std::max;
size_type p = 0, i, q;
find:
q = p + 1;
if (index[p] == threshold[q]){
if (q >= m) return false;
p = q;
goto find;
}
x = GetIndex ? p : index[p];
if (tag[p] == tag_t::INCREASE){
using std::min;
increase:
index[p] = min(index[p] + 2, threshold[q]);
threshold[p] = index[p] - 1;
}
else if (index[p] && (i = (index[p] - 1) & ~1) >= p){
index[p] = i;
threshold[p] = max(p - 1, (index[p] - 3) | 1);
}
else{
tag[p] = tag_t::INCREASE;
i = p | 1;
if (index[p] == i) goto increase;
index[p] = i;
threshold[p] = index[p] - 1;
}
y = index[p];
for (q = 0; q != p; ++q){
tag[q] = tag_t::DECREASE;
threshold[q] = max(q - 1, (index[q] - 3) | 1);
}
return true;
}
};
Does any one has a better implementation, i.e. run faster with the same memory or use less memory with the same speed?
I think that the C code below is closer to what Knuth had in mind. Undoubtedly there are ways to make it more elegant (in particular, I'm leaving some scaffolding in case it helps with experimentation), though I'm skeptical that the array w can be disposed of. If storage is really important for some reason, then steal the sign bit from the a array.
#include <stdbool.h>
#include <stdio.h>
enum {
N = 10,
T = 5
};
static void next(int a[], bool w[], int *r) {
bool found_r = false;
int j;
for (j = *r; !w[j]; j++) {
int b = a[j] + 1;
int n = a[j + 1];
if (b < (w[j + 1] ? n - (2 - (n & 1)) : n)) {
if ((b & 1) == 0 && b + 1 < n) b++;
a[j] = b;
if (!found_r) *r = j > 1 ? j - 1 : 0;
return;
}
w[j] = a[j] - 1 >= j;
if (w[j] && !found_r) {
*r = j;
found_r = true;
}
}
int b = a[j] - 1;
if ((b & 1) != 0 && b - 1 >= j) b--;
a[j] = b;
w[j] = b - 1 >= j;
if (!found_r) *r = j;
}
int main(void) {
typedef char t_less_than_n[T < N ? 1 : -1];
int a[T + 1];
bool w[T + 1];
for (int j = 0; j < T + 1; j++) {
a[j] = N - (T - j);
w[j] = true;
}
int r = 0;
do {
for (int j = T - 1; j > -1; j--) printf("%x", a[j]);
putchar('\n');
if (false) {
for (int j = T - 1; j > -1; j--) printf("%d", w[j]);
putchar('\n');
}
next(a, w, &r);
} while (a[T] == N);
}
I am trying to solve hacker rank similar pairs https://www.hackerrank.com/contests/101hack/challenges/similarpair problem. I cant figure out why its failing for large test cases. I am using segment trees to solve this problem in nlogn time. You can find my code below.
#include<iostream>
#include<vector>
using namespace std;
vector<int> graph[110001];
int T, ST[100001*4] = {0}, N, deg[100001] = {0};
void update(int node, int b, int e, int idx, int val) {
if(b > node || e < node) return;
if(b == e) {
ST[idx] += val;
return;
}
update(node, b, (b + e)/2, 2 * idx, val);
update(node, (b + e)/2 + 1, e, 2 * idx + 1, val);
ST[idx] = ST[2 * idx] + ST[2 * idx + 1];
}
long Query(int l, int r, int b, int e, int idx) {
if( l > e || r < b) return 0;
if(l <= b && r >= e) return ST[idx];
return Query(l, r, b, (b + e)/2, 2 * idx) + Query(l, r, (b + e)/2 + 1, e, 2 * idx + 1);
}
long long SimilarPairs(int node) {
int l = max(1, node - T), r = min(N, node + T);
long res = 0;
res = Query(l, r, 1, N, 1);
update(node, 1, N, 1, 1);
for(int i = 0; i < graph[node].size(); i++) {
res += SimilarPairs(graph[node][i]);
}
update(node, 1, N, 1, -1);
return res;
}
int main() {
long x, y, root, result, start;
cin >> N >> T;
for(int i = 0; i < N - 1; i++) {
cin >> x >> y;
graph[x].push_back(y);
deg[y]++;
}
for(int i = 1; i <= N; i++) if(!deg[i]) root = i;
result = SimilarPairs(root);
cout << result << endl;
cin.get();
return 0;
}
I get what you were doing. The problem is that you were missing some long longs. long is the same as an int (on 32 bits), so you must use long long everywhere, since the result does not necessarily fit in a 32 bit int.
This gets AC:
#include<iostream>
#include<vector>
using namespace std;
vector<int> graph[110001];
int T, N, deg[100001] = {0};
long long ST[100001*4] = {0};
void update(int node, int b, int e, int idx, int val) {
if(b > node || e < node) return;
if(b == e) {
ST[idx] += val;
return;
}
int m = (b + e) >> 1;
int q = idx << 1;
update(node, b, m, q, val);
update(node, m + 1, e, q + 1, val);
ST[idx] = ST[q] + ST[q+1];
}
long long Query(int l, int r, int b, int e, int idx) {
if( l > e || r < b) return 0;
if(l <= b && r >= e) return ST[idx];
int m = (b + e) >> 1;
int q = idx << 1;
return Query(l, r, b, m, q) + Query(l, r, m + 1, e, q + 1);
}
long long SimilarPairs(int node) {
int l = max(1, node - T), r = min(N, node + T);
long long res = 0;
res = Query(l, r, 1, N, 1);
update(node, 1, N, 1, 1);
for(int i = 0; i < graph[node].size(); i++) {
res += SimilarPairs(graph[node][i]);
}
update(node, 1, N, 1, -1);
return res;
}
int main() {
long x, y, root, start;
cin >> N >> T;
for(int i = 0; i < N - 1; i++) {
cin >> x >> y;
graph[x].push_back(y);
deg[y]++;
}
for(int i = 1; i <= N; i++) if(!deg[i]) root = i;
long long result = SimilarPairs(root);
cout << result << endl;
cin.get();
return 0;
}