```go
package main
import (
"fmt"
"math"
)
const eps = 1e-9
type Circle struct {
x, y, r int
}
type Point struct {
x, y float64
}
func dist(a, b Point) float64 {
dx := a.x - b.x
dy := a.y - b.y
return math.Sqrt(dx*dx + dy*dy)
}
func intersect(c1, c2 Circle) []Point {
x1 := float64(c1.x)
y1 := float64(c1.y)
r1 := float64(c1.r)
x2 := float64(c2.x)
y2 := float64(c2.y)
r2 := float64(c2.r)
dx := x2 - x1
dy := y2 - y1
d2 := dx*dx + dy*dy
d := math.Sqrt(d2)
if d > r1+r2+eps {
return nil
}
if d < math.Abs(r1-r2)-eps {
return nil
}
a := (r1*r1 - r2*r2 + d2) / (2 * d)
h2 := r1*r1 - a*a
if h2 < 0 {
h2 = 0
}
h := math.Sqrt(h2)
p2x := x1 + a*dx/d
p2y := y1 + a*dy/d
if h2 < eps {
return []Point{{p2x, p2y}}
}
rx := -dy * (h / d)
ry := dx * (h / d)
return []Point{
{p2x + rx, p2y + ry},
{p2x - rx, p2y - ry},
}
}
func main() {
var n int
fmt.Scan(&n)
circles := make([]Circle, n)
for i := 0; i < n; i++ {
fmt.Scan(&circles[i].x, &circles[i].y, &circles[i].r)
}
adj := make([][]bool, n)
for i := range adj {
adj[i] = make([]bool, n)
}
var allPoints []Point
for i := 0; i < n; i++ {
for j := i + 1; j < n; j++ {
pts := intersect(circles[i], circles[j])
if len(pts) > 0 {
adj[i][j] = true
adj[j][i] = true
}
allPoints = append(allPoints, pts...)
}
}
var unique []Point
for _, p := range allPoints {
found := false
for _, u := range unique {
if dist(p, u) < eps {
found = true
break
}
}
if !found {
unique = append(unique, p)
}
}
V := len(unique)
E := 0
for i := 0; i < n; i++ {
c := circles[i]
cnt := 0
for _, u := range unique {
cd := dist(Point{float64(c.x), float64(c.y)}, u)
if math.Abs(cd-float64(c.r)) < eps {
cnt++
}
}
if cnt > 0 {
E += cnt
}
}
visited := make([]bool, n)
var dfs func(u int)
dfs = func(u int) {
visited[u] = true
for v := 0; v < n; v++ {
if adj[u][v] && !visited[v] {
dfs(v)
}
}
}
C := 0
for i := 0; i < n; i++ {
if !visited[i] {
C++
dfs(i)
}
}
F := 1 + C + E - V
fmt.Println(F)
}
```