题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=24956
题意:给一些点和每个点上的权值。要求把所有路都连通。问取两个城市的人口和A,然后两个城市之间零代价连通,剩余路的长度为B,求A/B最大值。
思路:先最小生成树。
如果用Kruskal,则最后枚举小树上去掉哪条边,然后分别在边的两侧找出最大的人口,求和为A,而B为剩余路径长度。穷举得最大值。
如果Prim,穷举两个点,去掉他们形成的环上的最大边,而这个在初始加边的时候实现。靠,重新打的时候还是实现了很久,开了大量的数组来记录。加入新节点E,设原来已经得到的集合为W,则W中的点A到E的环上最大边即为当前A到E路径上的最大边。采用vector来存边,但还是要开一个mark数组记录到底是加了哪些边。
遗憾的是,len即总长度刚开始设为int致使无限出错。
还学了学低精度怎么转高精度,直接加就好。
输入时,double为%lf,float为%f;输出时,均为%f下次注意。
源码:
Kruskal:
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
using namespace std;
#define gmax(a,b) a>b?a:b
#define inf 99999999
#define LOCAL
int const MAXN = 1000+50;
int pa[MAXN],n,tot,use[MAXN];
double len;
//double dd[MAXN][MAXN];
struct D
{
int x,y,peo;
void init(int a,int b,int c){x=a;y=b;peo=c;}
}dot[MAXN];
struct E
{
int s,e;
double val;
void init(int a,int b,double c){s=a;e=b;val=c;}
}edge[MAXN*MAXN/2],rest[MAXN];/**/
double dis(int i,int j)
{
double s1 = ((dot[i].x-dot[j].x)*(dot[i].x-dot[j].x));
double s2 = ((dot[i].y-dot[j].y)*(dot[i].y-dot[j].y));
return sqrt(1.0*(s1+s2));
}
bool cmp(E a,E b)
{
return a.val<b.val;
}
int fi(int a)
{
if(a!=pa[a]) pa[a] = fi(pa[a]);
return pa[a];
}
vector<int>vv[MAXN];
void init()
{
int x,y,p;
for(int i=1; i<=n; i++){
scanf("%d%d%d",&x,&y,&p);
dot[i].init(x,y,p);
vv[i].clear();
}
tot = 0;
for(int i=1; i<=n; i++){
for(int j=i+1; j<=n; j++){
edge[tot].init(i,j,dis(i,j));
tot++;
}
}
// printf("tot = %d\n",tot);
for(int i=1; i<=n; i++)
pa[i] = i;
}
void Kruskal()
{
len = 0;
int ee = 0;
sort(edge,edge+tot,cmp);
for(int i=0; i<tot; i++){
int x = fi(edge[i].s);
int y = fi(edge[i].e);
if(x!=y){
// printf("x = %d, y = %d\n",x,y);
pa[x] = y;
len += edge[i].val;
rest[ee] = edge[i];
ee++;
int s = edge[i].s;int e = edge[i].e;
vv[s].push_back(e);
vv[e].push_back(s);
}
if(ee == n-1)
break;
}
// printf("len = %d\n",len);
}
int mmax;
void dfs(int a)
{
use[a] = 1;
mmax = max(mmax,dot[a].peo);
for(int i=0; i<vv[a].size(); i++)
if(use[vv[a][i]]==0){
dfs(vv[a][i]);
}
}
void solve()
{
// printf("len = %d\n",len);
double ans=0;
// printf("rest =\n");
// for(int i=0; i<n-1; i++){
// printf("s = %d,e = %d,val = %f\n",rest[i].s,rest[i].e,rest[i].val);
// }
// printf("vv");
// for(int i=1; i<=n; i++){
// printf("for %d vv is ",i);
// for(int j=0; j<vv[i].size(); j++)
// printf("%d ",vv[i][j]);
// printf("\n");
// }
for(int i=0; i<n-1; i++){
double A=0,B;
B = 1.0*(len - rest[i].val);
int x = rest[i].s; int y = rest[i].e;
mmax = 0;memset(use,0,sizeof(use));use[x] = 1;dfs(y);
// printf("mmax1 = %d\n",mmax);
A += mmax;mmax = 0;
memset(use,0,sizeof(use));use[y] = 1;dfs(x);A+=mmax;
// printf("mmax2 = %d\n",mmax);
// printf("for %d A = %f B = %f\n",i,A,B);
ans = max(ans,(1.0*A)/B);
}
printf("%.2f\n",ans);
}
int main()
{
// #ifdef LOCAL
// freopen("data.txt","r",stdin);
// freopen("data2.txt","w",stdout);
// #endif // LOCAL
int t;
scanf("%d", &t);
while(t--){
scanf("%d",&n);
init();
// check();
Kruskal();
solve();
}
return 0;
}
Prim:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
#define inf 99999999
#define LOCAL
int const MAXN = 1000+5;
double edge[MAXN][MAXN],maxcost[MAXN][MAXN],low[MAXN],use[MAXN],len;
int n,vis[MAXN],vv[MAXN][MAXN],mark[MAXN];
struct D
{
int x,y,val;
void init(int a,int b,int c){x=a;y=b;val=c;}
}dot[MAXN];
double dis(D a,D b)
{
double s1 = pow(a.x-b.x,2);
double s2 = pow(a.y-b.y,2);
return sqrt(s1+s2);
}
vector<int>lin[MAXN];
void init()
{
int x,y,val;
len = 0;
scanf("%d",&n);
for(int i=0; i<n; i++){
scanf("%d%d%d",&x,&y,&val);
dot[i].init(x,y,val);
lin[i].clear();
}
for(int i=0; i<n; i++){
for(int j=i; j<n; j++){
if(i==j)
edge[i][j] = inf;
else
edge[i][j] = edge[j][i] = dis(dot[i],dot[j]);
// if(i==1 && j==3){
// printf("edge[1][3] = %f\n",edge[1][3]);
// }
}
}
}
void dfs(int org,int st,double t)
{
int i;
vis[st] = 1;
double t0;
for(i=0; i<lin[st].size(); i++){
if(vis[lin[st][i]]==0){
t0 = max(t,edge[st][lin[st][i]]);
maxcost[org][lin[st][i]] = maxcost[lin[st][i]][org] = t0;
// printf("for org = %d,st = %d ,%d is %f\n",org,st,lin[st][i],t0);
dfs(org,lin[st][i],t0);
}
}
}
void Prim()
{
memset(maxcost,0,sizeof(maxcost));
memset(use,0,sizeof(use));
memset(vv,0,sizeof(vv));
int st = 0;
double t = edge[0][st];
for(int i=0; i<n; i++){
mark[i] = 0;
low[i] = edge[0][i];
if(low[i]<t){
t = low[i];
st = i;
}
}
use[0] = 1;
lin[0].push_back(st);
lin[st].push_back(0);
vv[st][0] = vv[0][st] = 1;
while(use[st]==0){
memset(vis,0,sizeof(vis));
dfs(st,st,t);
// printf("st = %d,t = %f\n",st,t);
// printf("low = \n");
// for(int i=0; i<n; i++)
// printf("%f ",low[i]);
// printf("\n");
use[st] = 1;
len += t;
// printf("len = %f\n",len);
t = inf;
for(int i=0; i<n; i++){
if(low[i]>edge[st][i] && use[i]==0){
low[i] = edge[st][i];
mark[i] = st;
}
}
for(int i=0; i<n; i++)
if(low[i]<t && use[i]==0){
t = low[i];
st = i;
}
lin[st].push_back(mark[st]);
lin[mark[st]].push_back(st);
vv[mark[st]][st] = vv[st][mark[st]] = 1;
// printf("st = %d\n",st);
}
// printf("maxcost = \n");
// for(int i=0; i<n; i++){
// for(int j=0; j<n; j++)
// printf("%f ",maxcost[i][j]);
// printf("\n");
// }
}
void solve()
{
double ans = 0;
// printf("len = %f\n",len);
for(int i=0; i<n; i++){
for(int j=i+1; j<n; j++){
double A = dot[i].val + dot[j].val;
double B;
if(vv[i][j]) B = len - edge[i][j];
else B = len - maxcost[i][j];
// printf("A = %f,B = %f\n",A,B);
ans = max(ans, A/B);
}
}
printf("%.2f\n",ans);
}
int main()
{
// #ifdef LOCAL
// freopen("data.txt","r",stdin);
// freopen("data3.txt","w",stdout);
// #endif // LOCAL
int t;
scanf("%d",&t);
while(t--){
init();
Prim();
solve();
}
return 0;
}