看了一晚上,还是不会,先把别人的代码保存下来,明天再看吧。
思路:最小生成树+枚举
1.朴素prim算法:
传送门:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <vector>
using namespace std;
#define N 1050
#define INF 1000000
struct point
{
double x,y;
int num;
}p[N];
int n;
double map[N][N],dist[N],A,B;
vector<int>vec[N];
double getdistance(point aa,point bb)
{
return sqrt((aa.x-bb.x)*(aa.x-bb.x)+(aa.y-bb.y)*(aa.y-bb.y));
}
int pre[N];
void prim()
{
for(int i=1;i<=n;++i)
dist[i]=INF*1.0;
double min_edge;
int min_p,now=1;
for(int i=1;i<n;++i)// 这里dist 表示到达已经更新好的点集的最小距离
{
min_edge=INF*1.0;
for(int i=1;i<=n;++i)
if(map[now][i]>0)
{
if(dist[i]>map[now][i])
dist[i]=map[now][i],pre[i]=now;
}
dist[now]=-1.0;
for(int i=1;i<=n;++i)
if(dist[i]>0&&dist[i]<min_edge)
{
min_edge=dist[i];
min_p=i;
}
vec[pre[min_p]].push_back(min_p); // 最小边有可能来自之前更新过的,这里WA
vec[min_p].push_back(pre[min_p]);
now=min_p;
B+=min_edge;
}
}
int vis[N];
int dfs(int u,int fa)
{
int max_num=p[u].num;
int ret=u;int tt;
for(int i=0;i<vec[u].size();++i)
if(vec[u][i]!=fa)
{
tt=dfs(vec[u][i],u);
if(max_num<p[tt].num)
max_num=p[tt].num,ret=tt;
}
return ret;
}
int main ()
{
//freopen("aa.txt","r",stdin);
//freopen("bb.txt","w",stdout);
int test;scanf("%d",&test);
while(test--)
{
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%lf%lf%d",&p[i].x,&p[i].y,&p[i].num);
for(int i=1;i<=n;++i)
{
for(int j=i+1;j<=n;++j)
map[i][j]=map[j][i]=getdistance(p[i],p[j]);
map[i][i]=0.0;
}
for(int i=0;i<=n;++i)
vec[i].clear();
B=0.0;
memset(pre,-1,sizeof(pre));
prim();
double ans=-1.0;
double res;int t1,t2;
for(int i=1;i<=n;++i)
for(int j=0;j<vec[i].size();++j) // 枚举边,对于这条割边两侧的连通图分别找出点权最大的点
{
t1=dfs(i,vec[i][j]);
t2=dfs(vec[i][j],i);
res=(p[t1].num+p[t2].num)/(B-map[i][vec[i][j]]);
if(res>ans)
ans=res;
}
ans+=(1e-8);
printf("%.2lf\n",ans);
}
//system("pause");
return 0;
}
2. prim + heap 算法
传送门:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <stack>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#define ll long long
#define inf 1<<30
#define PI acos(-1.0)
#define mem(a , b) memset(a , b ,sizeof(a))
using namespace std ;
struct kdq {
int s , e ;
double l ;
bool operator < (const kdq & fk)const {
return l > fk.l ;
}
} ;
inline void RD(int &ret) {
char c;
int flag = 1 ;
do {
c = getchar();
if(c == '-')flag = -1 ;
} while(c < '0' || c > '9') ;
ret = c - '0';
while((c=getchar()) >= '0' && c <= '9')
ret = ret * 10 + ( c - '0' );
ret *= flag ;
}
#define N 1111
double ed[N][N] , edM[N][N] ;
int x[N] , y[N], pop[N] ;
int n ;
double mst = 0 ;
double getdis(int i ,int j) {
return sqrt(1.0 * (x[i] - x[j]) * (x[i] - x[j]) + 1.0 * (y[i] - y[j]) * (y[i] - y[j])) ;
}
void init() {
cin >> n ;
for (int i = 1; i <= n ; i ++ ) {
RD(x[i]) ; RD(y[i]) ; RD(pop[i]) ;
}
for (int i = 1 ; i <= n ; i ++ ) {
for (int j = 1; j <= n ; j ++ ) {
if(i == j)ed[i][j] = 0 ;
else ed[i][j] = getdis(i , j) ;
}
}
mst = 0 ;
}
double dis[N] ;
int vis[N] ;
bool ok[N][N] ;
vector<int>E[N] ;
void prim() {
priority_queue<kdq>qe ;
for (int i = 1 ; i <= n ; i ++ ) {
dis[i] = ed[1][i] ;
E[i].clear() ;
}
mem(vis ,0) ;
mem(ok ,0) ;
for (int i = 1 ; i <= n ; i ++ ) {
qe.push((kdq) {1 , i , ed[1][i]}) ;
}
dis[1] = 0 , vis[1] = 1 ;
while(!qe.empty()) {
kdq tp = qe.top() ;
qe.pop() ;
if(vis[tp.e])continue ;
mst += ed[tp.s][tp.e] ;
vis[tp.e] = 1 ;
ok[tp.s][tp.e] = ok[tp.e][tp.s] = 1 ;
E[tp.s].push_back(tp.e) ;
E[tp.e].push_back(tp.s) ;
for (int i = 1 ; i <= n ; i ++ ) {
if(!vis[i] && dis[i] > ed[tp.e][i]) {
dis[i] = ed[tp.e][i] ;
qe.push((kdq){tp.e , i , ed[tp.e][i]}) ;
}
}
}
}
void dfs(int root ,int fa ,int now ,double MAX) {
edM[root][now] = MAX ;
int sz = E[now].size() ;
for (int i = 0 ; i < sz ; i ++ ) {
int e = E[now][i] ;
if(e == fa)continue ;
dfs(root , now , e , max(MAX , ed[now][e])) ;
}
}
void solve() {
init() ;
prim() ;
for (int i = 1 ; i <= n ; i ++ ) {
dfs(i , -1 , i , 0) ;
}
double ans = -1 ;
for (int i = 1 ; i <= n ; i ++ ) {
for (int j = 1 ; j < i ; j ++ ) {
if(ok[i][j])
ans = max(ans , (pop[i] + pop[j]) * 1.0 / (mst - ed[i][j])) ;
else
ans = max(ans , (pop[i] + pop[j]) * 1.0 / (mst - edM[i][j])) ;
}
}
printf("%.2f\n",ans) ;
}
int main() {
int _ ;cin >> _ ;while(_ -- )solve() ;
return 0;
}
3.kruskal算法
传送门:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 2010;
const int maxe = 1000010;
int pre[maxn];
int n;
struct Point{
double x, y, c;
}point[maxn];
int find(int x){
int s;
for(s = x; pre[s] >= 0; s = pre[s]);
while(x != s){
int t = pre[x];
pre[x] = s;
x = t;
}
return s;
}
void Union(int x, int y){
int u = find(x);
int v = find(y);
if(u == v) return;
if(pre[u] > pre[v]){
pre[u] += pre[v];
pre[v] = u;
}else{
pre[v] += pre[u];
pre[u] = v;
}
}
void input(){
scanf("%d", &n);
for(int i = 0; i < n; i ++){
scanf("%lf%lf%lf", &point[i].x, &point[i].y, &point[i].c);
}
}
struct Edge{
double w;
int u, v;
int next;
}e[maxe];
int head[maxn], index;
struct EDGE{
int u, v;
double w;
friend bool operator < (const EDGE &a, const EDGE &b){
return a.w < b.w;
}
}edge[maxe];
int m;
double calc(Point a, Point b){
return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}
void add_EDGE(int u, int v, double w){
edge[m].u = u;
edge[m].v = v;
edge[m].w = w;
m++;
}
void build(){
m = 0;
for(int i = 0; i < n - 1; i ++){
for(int j = i+1; j < n; j ++){
double dist = calc(point[i], point[j]);
add_EDGE(i, j, dist);
}
}
}
void add_edge(int u, int v, double w){
e[index].u = u, e[index].v = v, e[index].w = w, e[index].next = head[u];
head[u] = index ++;
}
double kruskal(){
double ans = 0.0;
int num = 0;
memset(pre, -1, sizeof pre);
sort(edge, edge + m);
index = 0;
memset(head, -1, sizeof head);
for(int i = 0; i < m; i ++){
int u = edge[i].u, v = edge[i].v;
if(find(u) != find(v)){
ans += edge[i].w;
num ++;
Union(u, v);
add_edge(u, v, edge[i].w);
add_edge(v, u, edge[i].w);
}
if(num == n - 1) break;
}
return ans;
}
double cost[maxn][maxn];
int vis[maxn];
void dfs(int u, int uu, double max_num){
vis[uu] = 1;
for(int i = head[uu]; i != -1; i = e[i].next){
if(vis[e[i].v] == 1) continue;
//max_num= max(max_num, e[i].w);
//cost[u][e[i].v] = max_num;
//printf("-- %f\n", max_num);
dfs(u, e[i].v, cost[u][e[i].v] = max(max_num, e[i].w));
//printf("++ %f\n", max_num);
//zsystem("pause");
}
}
void solve(){
double mst = kruskal();
for(int i = 0; i < n; i ++) {
memset(vis, 0, sizeof vis);
dfs(i, i, -1.0);
}
double ans = -1;
for(int i = 0; i < m; i ++){
double tmp = (point[edge[i].u].c + point[edge[i].v].c) / (mst - cost[edge[i].u][edge[i].v]);
//printf("--- %f\n", tmp);
ans = max(ans, tmp);
}
/*
这两种枚举都行
for(int i = 0; i < n - 1; i ++){
for(int j = i+1; j < n; j ++){
double tmp = (point[i].c + point[j].c) / (mst - cost[i][j]);
//printf("--- %f\n", tmp);
if(tmp > ans) ans = tmp;
}
}
*/
printf("%.2f\n", ans);
}
int main(){
//freopen("in.txt", "r", stdin);
int tcase;
scanf("%d", &tcase);
while(tcase --){
input();
build();
solve();
}
return 0;
}