首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >贪婪搜索是P=NP之TSP问题的近似解

贪婪搜索是P=NP之TSP问题的近似解

作者头像
Zeusro
修改于 2025-06-20 23:33:59
修改于 2025-06-20 23:33:59
1340
举报
代码语言:TXT
AI代码解释
复制
    Where there is a will there's a way

底层模型

代码语言:go
AI代码解释
复制
package v1

import (
	"math/rand"
	"time"
)

type City struct {
	Coordinates
	Name     string
	Distance float64
}

// Coordinates 经纬度
type Coordinates struct {
	Latitude  float64 `yaml:"latitude"`  //纬度
	Longitude float64 `yaml:"longitude"` //经度
}

// USCities 包含美国各州不同区域的至少 50 个城市
var USCities = []City{
	City{
		Name: "New York",

		Coordinates: Coordinates{
			Latitude:  40.7128,
			Longitude: -74.0060,
		},
		Distance: 0,
	},
	City{
		Name: "Los Angeles",

		Coordinates: Coordinates{
			Latitude:  34.0522,
			Longitude: -118.2437,
		},
		Distance: 0,
	},
	City{
		Name: "Chicago",

		Coordinates: Coordinates{
			Latitude:  41.8781,
			Longitude: -87.6298,
		},
		Distance: 0,
	},
	City{
		Name: "Houston",

		Coordinates: Coordinates{
			Latitude:  29.7604,
			Longitude: -95.3698,
		},
		Distance: 0,
	},
	City{
		Name: "Phoenix",

		Coordinates: Coordinates{
			Latitude:  33.4484,
			Longitude: -112.0740,
		},
		Distance: 0,
	},
	City{
		Name: "Philadelphia",

		Coordinates: Coordinates{
			Latitude:  39.9526,
			Longitude: -75.1652,
		},
		Distance: 0,
	},
	City{
		Name: "San Antonio",

		Coordinates: Coordinates{
			Latitude:  29.4241,
			Longitude: -98.4936,
		},
		Distance: 0,
	},
	City{
		Name: "San Diego",

		Coordinates: Coordinates{
			Latitude:  32.7157,
			Longitude: -117.1611,
		},
		Distance: 0,
	},
	City{
		Name: "Dallas",

		Coordinates: Coordinates{
			Latitude:  32.7767,
			Longitude: -96.7970,
		},
		Distance: 0,
	},
	City{
		Name: "San Jose",

		Coordinates: Coordinates{
			Latitude:  37.3382,
			Longitude: -121.8863,
		},
		Distance: 0,
	},
	City{
		Name: "Austin",

		Coordinates: Coordinates{
			Latitude:  30.2672,
			Longitude: -97.7431,
		},
		Distance: 0,
	},
	City{
		Name: "Jacksonville",

		Coordinates: Coordinates{
			Latitude:  30.3322,
			Longitude: -81.6557,
		},
		Distance: 0,
	},
	City{
		Name: "Fort Worth",

		Coordinates: Coordinates{
			Latitude:  32.7555,
			Longitude: -97.3308,
		},
		Distance: 0,
	},
	City{
		Name: "Columbus",

		Coordinates: Coordinates{
			Latitude:  39.9612,
			Longitude: -82.9988,
		},
		Distance: 0,
	},
	City{
		Name: "Charlotte",

		Coordinates: Coordinates{
			Latitude:  35.2271,
			Longitude: -80.8431,
		},
		Distance: 0,
	},
	City{
		Name: "San Francisco",

		Coordinates: Coordinates{
			Latitude:  37.7749,
			Longitude: -122.4194,
		},
		Distance: 0,
	},
	City{
		Name: "Indianapolis",

		Coordinates: Coordinates{
			Latitude:  39.7684,
			Longitude: -86.1581,
		},
		Distance: 0,
	},
	City{
		Name: "Seattle",

		Coordinates: Coordinates{
			Latitude:  47.6062,
			Longitude: -122.3321,
		},
		Distance: 0,
	},
	City{
		Name: "Denver",

		Coordinates: Coordinates{
			Latitude:  39.7392,
			Longitude: -104.9903,
		},
		Distance: 0,
	},
	City{
		Name: "Washington",

		Coordinates: Coordinates{
			Latitude:  38.9072,
			Longitude: -77.0369,
		},
		Distance: 0,
	},
	City{
		Name: "Boston",

		Coordinates: Coordinates{
			Latitude:  42.3601,
			Longitude: -71.0589,
		},
		Distance: 0,
	},
	City{
		Name: "El Paso",

		Coordinates: Coordinates{
			Latitude:  31.7619,
			Longitude: -106.4850,
		},
		Distance: 0,
	},
	City{
		Name: "Nashville",

		Coordinates: Coordinates{
			Latitude:  36.1627,
			Longitude: -86.7816,
		},
		Distance: 0,
	},
	City{
		Name: "Detroit",

		Coordinates: Coordinates{
			Latitude:  42.3314,
			Longitude: -83.0458,
		},
		Distance: 0,
	},
	City{
		Name: "Oklahoma City",

		Coordinates: Coordinates{
			Latitude:  35.4676,
			Longitude: -97.5164,
		},
		Distance: 0,
	},
	City{
		Name: "Portland",

		Coordinates: Coordinates{
			Latitude:  45.5051,
			Longitude: -122.6750,
		},
		Distance: 0,
	},
	City{
		Name: "Las Vegas",

		Coordinates: Coordinates{
			Latitude:  36.1699,
			Longitude: -115.1398,
		},
		Distance: 0,
	},
	City{
		Name: "Memphis",

		Coordinates: Coordinates{
			Latitude:  35.1495,
			Longitude: -90.0490,
		},
		Distance: 0,
	},
	City{
		Name: "Louisville",

		Coordinates: Coordinates{
			Latitude:  38.2527,
			Longitude: -85.7585,
		},
		Distance: 0,
	},
	City{
		Name: "Baltimore",

		Coordinates: Coordinates{
			Latitude:  39.2904,
			Longitude: -76.6122,
		},
		Distance: 0,
	},
	City{
		Name: "Milwaukee",

		Coordinates: Coordinates{
			Latitude:  43.0389,
			Longitude: -87.9065,
		},
		Distance: 0,
	},
	City{
		Name: "Albuquerque",

		Coordinates: Coordinates{
			Latitude:  35.0844,
			Longitude: -106.6504,
		},
		Distance: 0,
	},
	City{
		Name: "Tucson",

		Coordinates: Coordinates{
			Latitude:  32.2226,
			Longitude: -110.9747,
		},
		Distance: 0,
	},
	City{
		Name: "Fresno",

		Coordinates: Coordinates{
			Latitude:  36.7378,
			Longitude: -119.7871,
		},
		Distance: 0,
	},
	City{
		Name: "Mesa",

		Coordinates: Coordinates{
			Latitude:  33.4152,
			Longitude: -111.8315,
		},
		Distance: 0,
	},
	City{
		Name: "Sacramento",

		Coordinates: Coordinates{
			Latitude:  38.5816,
			Longitude: -121.4944,
		},
		Distance: 0,
	},
	City{
		Name: "Atlanta",

		Coordinates: Coordinates{
			Latitude:  33.7490,
			Longitude: -84.3880,
		},
		Distance: 0,
	},
	City{
		Name: "Kansas City",

		Coordinates: Coordinates{
			Latitude:  39.0997,
			Longitude: -94.5786,
		},
		Distance: 0,
	},
	City{
		Name: "Colorado Springs",

		Coordinates: Coordinates{
			Latitude:  38.8339,
			Longitude: -104.8214,
		},
		Distance: 0,
	},
	City{
		Name: "Miami",

		Coordinates: Coordinates{
			Latitude:  25.7617,
			Longitude: -80.1918,
		},
		Distance: 0,
	},
	City{
		Name: "Raleigh",

		Coordinates: Coordinates{
			Latitude:  35.7796,
			Longitude: -78.6382,
		},
		Distance: 0,
	},
	City{
		Name: "Omaha",

		Coordinates: Coordinates{
			Latitude:  41.2565,
			Longitude: -95.9345,
		},
		Distance: 0,
	},
	City{
		Name: "Long Beach",

		Coordinates: Coordinates{
			Latitude:  33.7701,
			Longitude: -118.1937,
		},
		Distance: 0,
	},
	City{
		Name: "Virginia Beach",

		Coordinates: Coordinates{
			Latitude:  36.8529,
			Longitude: -75.9780,
		},
		Distance: 0,
	},
	City{
		Name: "Oakland",

		Coordinates: Coordinates{
			Latitude:  37.8044,
			Longitude: -122.2711,
		},
		Distance: 0,
	},
	City{
		Name: "Minneapolis",

		Coordinates: Coordinates{
			Latitude:  44.9778,
			Longitude: -93.2650,
		},
		Distance: 0,
	},
	City{
		Name: "Tulsa",

		Coordinates: Coordinates{
			Latitude:  36.1539,
			Longitude: -95.9928,
		},
		Distance: 0,
	},
	City{
		Name: "Arlington",

		Coordinates: Coordinates{
			Latitude:  32.7357,
			Longitude: -97.1081,
		},
		Distance: 0,
	},
	City{
		Name: "New Orleans",

		Coordinates: Coordinates{
			Latitude:  29.9511,
			Longitude: -90.0715,
		},
		Distance: 0,
	},
	City{
		Name: "Wichita",

		Coordinates: Coordinates{
			Latitude:  37.6872,
			Longitude: -97.3301,
		},
		Distance: 0,
	},
}

// RandomUSCity 生成一个随机的美国城市示例
func RandomUSCity() City {
	// 示例城市列表(可扩展)
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	return USCities[r.Intn(len(USCities))]
}

func IsInContinentalUS(lat, lon float64) bool {
	return lat >= 24.5 && lat <= 49.4 && lon >= -124.8 && lon <= -66.9
}

主体函数

代码语言:go
AI代码解释
复制
package v2

import (
	"math"

	"github.com/zeusro/system/function/local"
	v1 "github.com/zeusro/system/problems/np/model/v1"
)

type Salesman struct {
	TodoCity map[string]v1.City // 计划旅行的所有城市列表
	Plan     []v1.City          // 实际执行的旅行计划,是一个环形队列,这里简单用数组表示
	KURO     float64            // KURO是日本动画《K》里面的一个角色,这里用来表示旅行的总距离,是一种浪漫主义表达手法
	Truth    bool               //问题是否可解
}

func NewSalesman(cities []v1.City) *Salesman {
	if len(cities) < 2 {
		panic("至少需要两个城市才能进行旅行")
	}
	s := &Salesman{
		TodoCity: make(map[string]v1.City),
	}
	// 拿到"地图",获取USA所有城市背景之后,直接map化
	// 初始化旅行城市列表
	for _, c := range cities {
		s.TodoCity[c.Name] = c
	}
	s.Plan = make([]v1.City, len(cities)+1) // 预分配空间,+1是为了回到起点城市
	return s
}

// Travel 踏上寻找n的旅程
func (s *Salesman) TravelN(cityName string, n int) {
	// 上一次的目的地是这一次的起点城市。0比较特殊,代表出发城市。
	// 起点城市不在旅行计划中
	current := s.TodoCity[cityName]
	if n >= 1 {
		s.Plan[n] = current
	}
	delete(s.TodoCity, cityName) //由于计划是单线程,不用考虑线程安全
	//边界的判断条件是剩余旅行城市=0
	if n == 0 {
		s.Plan[0] = s.Plan[len(s.Plan)-1] // 确保最后一个城市是起点城市
		return
	}
	var nextCity v1.City
	minDistance := math.MaxFloat64
	for _, city := range s.TodoCity {
		distance := local.Haversine(city.Latitude, city.Longitude, current.Latitude, current.Longitude)
		if distance < minDistance {
			minDistance = distance
			nextCity = city
		}
	}
	s.Plan[n].Distance = minDistance
	s.KURO += minDistance                     // 累加距离
	s.TravelN(nextCity.Name, len(s.TodoCity)) // 递归调用
}

func (s *Salesman) GetK() float64 {
	if s.IsSolvable(s.Plan) {
		return s.KURO
	}
	return 0
}

func (s *Salesman) IsSolvable(city []v1.City) bool {
	if len(s.TodoCity) == 0 && len(s.Plan) == (len(city)+1) {
		s.Truth = true
	}
	return s.Truth
}

辅助方法

代码语言:go
AI代码解释
复制
// haversine 📌 Haversine 公式:计算地球上两点的距离
// 传入两点的经纬度,返回两点之间的距离(单位:公里)
func Haversine(lat1, lon1, lat2, lon2 float64) float64 {
	const R = 6371 // 地球半径(单位:公里)

	dLat := degreesToRadians(lat2 - lat1)
	dLon := degreesToRadians(lon2 - lon1)

	a := math.Sin(dLat/2)*math.Sin(dLat/2) +
		math.Cos(degreesToRadians(lat1))*math.Cos(degreesToRadians(lat2))*
			math.Sin(dLon/2)*math.Sin(dLon/2)

	c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))
	return R * c
}

func degreesToRadians(deg float64) float64 {
	return deg * math.Pi / 180
}

测试用例

代码语言:go
AI代码解释
复制
package v2

import (
	"fmt"
	"testing"

	v1 "github.com/zeusro/system/problems/np/model/v1"
)

// 不打印
// ok  	github.com/zeusro/system/problems/np/model/v2	0.265s
// 打印
// ok  	github.com/zeusro/system/problems/np/model/v2	0.455s
func TestTravelN(t *testing.T) {
	s := NewSalesman(v1.USCities)
	// current := ConvertCityFromV1(v1.RandomUSCity())
	current := v1.USCities[0]
	// 直接指定起点城市,避免随机性
	s.TravelN(current.Name, len(s.TodoCity))
	if !s.IsSolvable(v1.USCities) {
		t.Fatal("旅行计划不可行")
	}
	start := 0
	for i := len(s.Plan) - 1; i > 0; i-- {
		fmt.Printf("%v:%+v\n", start, s.Plan[i])
		start++
	}
	fmt.Printf("跨越漫长的旅程(%v km),终于见到KURO\n", s.KURO)
}

// BenchmarkTravelN-8   	   15686	     74104 ns/op	   14696 B/op	       9 allocs/op
func BenchmarkTravelN(b *testing.B) {
	for i := 0; i < b.N; i++ {
		s := NewSalesman(v1.USCities)
		current := v1.RandomUSCity()
		s.TravelN(current.Name, len(s.TodoCity))
	}
}

数学证明

代码语言:txt
AI代码解释
复制
1:t=0
2:x=x && y=y && z=z && 1=1
3:P!=NP

在当前的数学符号系统里面,该问题不可解。

所有解法,只能无限逼近全局最优解。

https://github.com/zeusro/math/blob/main/it/P%3DNP.md

结论

代码语言:TXT
AI代码解释
复制
    踏上旅程,寻找真我

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档