package main
import (
"bufio"
"fmt"
"os"
)
type Edge struct {
to int
id int
}
type RawEdge struct {
u, v int
}
var dp_global []int32
var new_dp_global []int32
func init() {
dp_global = make([]int32, 2005*2005)
new_dp_global = make([]int32, 2005*2005)
for i := range dp_global {
dp_global[i] = -1
}
for i := range new_dp_global {
new_dp_global[i] = -1
}
}
func main() {
scanner := bufio.NewScanner(os.Stdin)
scanner.Split(bufio.ScanWords)
readInt := func() int {
if !scanner.Scan() {
return 0
}
res := 0
for _, b := range scanner.Bytes() {
res = res*10 + int(b-'0')
}
return res
}
n := readInt()
m := readInt()
if n == 0 {
return
}
adj_undir := make([][]Edge, n+1)
edgeList := make([]RawEdge, m)
for i := 0; i < m; i++ {
u := readInt()
v := readInt()
adj_undir[u] = append(adj_undir[u], Edge{v, i})
adj_undir[v] = append(adj_undir[v], Edge{u, i})
edgeList[i] = RawEdge{u, v}
}
timer := 0
tin := make([]int, n+1)
low := make([]int, n+1)
isBridge := make([]bool, m)
var dfs_bridge func(u, edgeID int)
dfs_bridge = func(u, edgeID int) {
timer++
tin[u] = timer
low[u] = timer
for _, e := range adj_undir[u] {
if e.id == edgeID {
continue
}
v := e.to
if tin[v] != 0 {
if tin[v] < low[u] {
low[u] = tin[v]
}
} else {
dfs_bridge(v, e.id)
if low[v] < low[u] {
low[u] = low[v]
}
if low[v] > tin[u] {
isBridge[e.id] = true
}
}
}
}
dfs_bridge(1, -1)
comp := make([]int, n+1)
compCount := 0
var S []int
S = append(S, 0)
var dfs_comp func(u, c int)
dfs_comp = func(u, c int) {
comp[u] = c
S[c]++
for _, e := range adj_undir[u] {
if !isBridge[e.id] && comp[e.to] == 0 {
dfs_comp(e.to, c)
}
}
}
for i := 1; i <= n; i++ {
if comp[i] == 0 {
compCount++
S = append(S, 0)
dfs_comp(i, compCount)
}
}
adj := make([][]int, compCount+1)
for i := 0; i < m; i++ {
if isBridge[i] {
u := edgeList[i].u
v := edgeList[i].v
cu := comp[u]
cv := comp[v]
adj[cu] = append(adj[cu], cv)
adj[cv] = append(adj[cv], cu)
}
}
W := make([]int, compCount+1)
F := make([][]int32, compCount+1)
var dfs_dp func(u, p int)
dfs_dp = func(u, p int) {
W[u] = S[u]
var children []int
for _, v := range adj[u] {
if v != p {
children = append(children, v)
dfs_dp(v, u)
W[u] += W[v]
}
}
valid_states := make([]int, 0, 1024)
valid_states = append(valid_states, 0)
dp_global[0] = 0
for _, v := range children {
new_valid := make([]int, 0, 1024)
for _, state := range valid_states {
k := state / 2005
m_val := state % 2005
val := dp_global[state]
for c := 1; c <= W[v]; c++ {
fc := F[v][c]
if fc == -1 {
continue
}
nval := val + fc
state1 := (k+c)*2005 + m_val
if new_dp_global[state1] == -1 {
new_valid = append(new_valid, state1)
}
if nval > new_dp_global[state1] {
new_dp_global[state1] = nval
}
state2 := k*2005 + (m_val + c)
if new_dp_global[state2] == -1 {
new_valid = append(new_valid, state2)
}
if nval > new_dp_global[state2] {
new_dp_global[state2] = nval
}
}
}
for _, state := range valid_states {
dp_global[state] = -1
}
for _, state := range new_valid {
dp_global[state] = new_dp_global[state]
new_dp_global[state] = -1
}
valid_states = new_valid
}
F[u] = make([]int32, W[u]+1)
for i := range F[u] {
F[u][i] = -1
}
for _, state := range valid_states {
k := state / 2005
m_val := state % 2005
val := dp_global[state]
K_out := S[u] + k
M_out := S[u] + m_val
pairs := val + int32(K_out*M_out)
if pairs > F[u][K_out] {
F[u][K_out] = pairs
}
if pairs > F[u][M_out] {
F[u][M_out] = pairs
}
}
for _, state := range valid_states {
dp_global[state] = -1
}
}
dfs_dp(1, 0)
var maxPairs int32 = 0
for c := 1; c <= W[1]; c++ {
if F[1][c] > maxPairs {
maxPairs = F[1][c]
}
}
fmt.Println(maxPairs)
}