非正规做法,一个一个的暴,减一下枝,还得采用sort,qsort居然过不了……
#include <cstdio> #include <cmath> #include <cstdlib> #include <algorithm> using namespace std; #define LL long long struct node{ int u, v, no; LL dis; }; int n, len, pos, p[1010], num[1010][2]; double maxx; node v[500010], cnt[1010]; LL dist(int i, int j){ return (LL)(num[i][0] - num[j][0]) * (num[i][0] - num[j][0]) + (LL)(num[i][1] - num[j][1]) * (num[i][1] - num[j][1]); } bool cmp(const node &p1, const node &p2) { return p1.dis < p2.dis; } int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); } void Kruskal(){ sort(v, v + len, cmp); maxx = 0; pos = 0; int k = n - 1; for(int i = 0; i < n; ++i) p[i] = i; for(int i = 0; i < len; ++i){ int x = find(v[i].u); int y = find(v[i].v); if(x!=y){ maxx += sqrt((double)v[i].dis); p[x] = y; cnt[pos] = v[i]; cnt[pos++].no = i; --k; if(!k) break; } } } void solve(){ double t = maxx; for(int k = 0; k < pos; ++k){ if(!cnt[k].u) continue; double e = t - sqrt((double)cnt[k].dis); for(int i = 0; i < n; ++i) p[i] = i; for(int i = 0; i < pos; ++i) if(i != k){ int x = find(cnt[i].u); int y = find(cnt[i].v); p[x] = y; } for(int i = cnt[k].no + 1; i < len; ++i){ int x1 = find(v[i].u); int y1 = find(v[i].v); if(x1 != y1){ e += sqrt((double)v[i].dis); if(maxx < e) maxx = e; break; } } } } int main() { //freopen("in.txt", "r", stdin); int t, k; scanf("%d", &t); while(t--){ scanf("%d %d", &n, &k); for(int i = 0; i < n; ++i) scanf("%d %d", &num[i][0], &num[i][1]); len = 0; for(int i = 0; i < n; ++i) for(int j = i+1; j < n; ++j){ v[len].dis = dist(i, j); v[len].u = i; v[len++].v = j; } Kruskal(); solve(); printf("%.2lf ", maxx * k); } return 0; } 第二次做:用dfs+并查集,速度果然提高了许多 #include <cstdio> #include <cmath> #include <cstdlib> #include <algorithm> using namespace std; #define LL long long struct node{ int u, v; LL dis; }; int n, len, pos, p[1010], num[1010][2], head[1010], next[2010][3]; double maxx, cnt; node v[500010]; LL dist(int i, int j){ return (LL)(num[i][0] - num[j][0]) * (num[i][0] - num[j][0]) + (LL)(num[i][1] - num[j][1]) * (num[i][1] - num[j][1]); } bool cmp(const node &p1, const node &p2) { return p1.dis < p2.dis; } int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); } void add(int u, int v, int i){ next[pos][1] = v; next[pos][2] = i; next[pos][0] = head[u]; head[u] = pos++; } void Kruskal(){ sort(v, v + len, cmp); maxx = 0; pos = 0; int k = n - 1; for(int i = 0; i < n; ++i) p[i] = i; for(int i = 0; i < len; ++i){ int x = find(v[i].u); int y = find(v[i].v); if(x!=y){ maxx += sqrt((double)v[i].dis); p[x] = y; add(v[i].u, v[i].v, i); add(v[i].v, v[i].u, i); --k; if(!k) break; } } } void dfs(int cur, int fa){ for(int i = head[cur]; i != -1; i = next[i][0]){ int u = next[i][1]; int no = next[i][2]; if(u != fa){ dfs(u, cur); int x = find(cur); int y = find(u); if(u && cur){ double t = maxx - sqrt(double(v[no].dis)); for(int j = no + 1; j < len; ++j){ int x1 = find(v[j].u); int y1 = find(v[j].v); if(x1 != y1 && (x1 == y || y1 == y)){ cnt = max(cnt, t + sqrt(double(v[j].dis))); break; } } } p[x] = y; } } } int main() { // freopen("in.txt", "r", stdin); int t, k; scanf("%d", &t); while(t--){ scanf("%d %d", &n, &k); for(int i = 0; i < n; ++i) scanf("%d %d", &num[i][0], &num[i][1]), head[i] = -1; len = 0; for(int i = 0; i < n; ++i) for(int j = i+1; j < n; ++j){ v[len].dis = dist(i, j); v[len].u = i; v[len++].v = j; } Kruskal(); for(int i = 0; i < n; ++i) p[i] = i; cnt = maxx; dfs(0, -1); printf("%.2lf ", cnt * k); } return 0; } 第三次做:采用普里姆算法,果然快了很多,适用于稠密图,也就是边比较多的图,N^2的算法,网上大多数采用普里姆算法+树形dp,我是采用普里姆算法然后dfs优化做的,c++也照样过 #include <cstdio> #include <cmath> #include <cstdlib> #include <algorithm> using namespace std; #define LL long long LL inf = 10000000000000000LL; int n, dfs_cnt, p[1010], num[1010][2], head[1010], next[2010][2]; double maxx, q; bool flag; LL v[1005][1005], cnt[1010], arr[1005][1005]; LL dist(int i, int j) { return (LL)(num[i][0] - num[j][0]) * (num[i][0] - num[j][0]) + (LL)(num[i][1] - num[j][1]) * (num[i][1] - num[j][1]); } void add(int u, int v){ next[dfs_cnt][1] = v; next[dfs_cnt][0] = head[u]; head[u] = dfs_cnt++; } void prim() { maxx = 0, dfs_cnt = 0; for(int i = 1; i < n; ++i){ cnt[i] = v[0][i]; p[i] = 0; } cnt[0] = 0, p[0] = 0; for(int i = 1; i < n; ++i){ int k = 0; LL c = inf; for(int j = 1; j < n; ++j) if(cnt[j] != 0 && cnt[j] < c){ c = cnt[j]; k = j; } add(p[k], k); add(k, p[k]); maxx += sqrt(double(c)); cnt[k] = 0; for(int j = 1; j < n; ++j) if(cnt[j] != 0 && v[k][j] < cnt[j]){ cnt[j] = v[k][j]; p[j] = k; } } } double tarjan(int cur, int fa, int pos, LL f){ double c = inf; for(int i = head[cur]; i != -1; i = next[i][0]){ int u = next[i][1]; if(u != fa){ c = min(c, tarjan(u, cur, pos, f)); if(arr[u][pos] != f) c = min(c, sqrt(double(arr[u][pos])) - sqrt(double(f))); else if(flag) c = min(c, 0.0); else flag = 1; //printf("%.2lf ", c); } } return c; } void dfs(int cur, int fa){ for(int i = head[cur]; i != -1; i = next[i][0]){ int u = next[i][1]; if(u != fa){ dfs(u, cur); if(u && cur){ double c = inf; for(int j = 0; j < n; ++j) if(j != cur) c = min(c, sqrt(double(v[u][j])) - sqrt(double(v[u][cur]))); flag = 0; if(arr[u][cur] == v[u][cur]) flag = 1; else c = min(c, sqrt(double(arr[u][cur]))); c = min(c, tarjan(u, cur, cur, v[u][cur])); maxx = max(maxx, q + c); } v[u][cur] = v[cur][u] = inf; for(int j = 0; j < n; ++j) if(v[cur][j] == inf || v[u][j] == inf) v[cur][j] = inf; else v[cur][j] = min(v[cur][j], v[u][j]); } } } int main() { // freopen("in.txt", "r", stdin); int t, k; scanf("%d", &t); while(t--){ scanf("%d %d", &n, &k); for(int i = 0; i < n; ++i) scanf("%d %d", &num[i][0], &num[i][1]), head[i] = -1; for(int i = 0; i < n; ++i){ arr[i][i] = v[i][i] = inf; for(int j = i + 1; j < n; ++j) if(i != j) arr[i][j] = arr[j][i] = v[i][j] = v[j][i] = dist(i, j); } prim(); q = maxx; dfs(0, -1); printf("%.2lf ", maxx * k); } return 0; }