VJ 1069 新年趣事之红包
描述
xiaomengxian一进门,发现外公、外婆、叔叔、阿姨……都坐在客厅里等着 他呢。经过仔细观察,xiaomengxian发现他们所有人正好组成了一个凸多边形。最重要的是,他们每个人手里都拿着一个红包(^o^)。于是非常心 急,xiaomengxian决定找一条最短的路线,拿到所有的红包。
假设屋里共有N个人拿着红包,把他们分别从1到N编号。其中,编号为1的人就坐在大门口,xiaomengxian必须从这里出发去拿其它的红包。一条合法的路线必须经过所有的点一次且仅一次。
格式
输入格式
第一行为一个整数N(1<=N<=800)。
以下N行,每行两个实数Xi,Yi,表示该点的坐标。
各个点按照逆时针顺序依次给出。
输出格式
一个实数,表示最短的路线长度(保留三位小数)。
限制
各个测试点1s
题解:基本上都说是DP,但是因为我DP太弱。。根本不敢打,而且打了也不对。。于是就去写了克鲁斯卡尔求最小生成树,感觉并没有什么问题,欢迎各位大牛与我探讨
CODE:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #define REP(i, s, n) for(int i = s; i <= n; i ++) #define REP_(i, s, n) for(int i = n; i >= s; i --) #define MAX_N 800 + 10 using namespace std; int n, f[MAX_N]; double x[MAX_N], y[MAX_N]; struct node{ int u, v; double w; }E[700000]; bool cmp(node a, node b){ return a.w < b.w; } int find(int x){ if(f[x] == x) return x; return f[x] = find(f[x]); } int main(){ scanf("%d", &n); int sum = 0; REP(i, 1, n) scanf("%lf%lf", &x[i], &y[i]); REP(i, 1, n) f[i] = i; REP(i, 1, n - 1) REP(j, i + 1, n){ E[++ sum].u = i; E[sum].v = j; E[sum].w = sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j])); } double ans = 0; sort(E + 1, E + sum + 1, cmp); REP(i, 1, sum){ int rx = find(E[i].u), ry = find(E[i].v); if(rx == ry) continue; f[ry] = rx; ans += E[i].w; } printf("%.3lf", ans); return 0; }