POJ 4081 Qin Shi Huang's National Road System

看了一晚上,还是不会,先把别人的代码保存下来,明天再看吧。

思路:最小生成树+枚举


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;
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值