给定 \(n\) 个点 \((n\leq2000)\),在第 \(i\) 个点上建立一个基站需要 \(c_i\) 的代价,连接两个点需要 \((|x_i-x_j|+|y_i-y_j|)(k_i+k_j)\) 的代价。对于一个点要么建立基站,要么连接建立基站的点。问最小代价是多少,同时输出建立基站的点和线路。

Solution

这个万年老题到底被出过多少遍了啊

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 2005;

struct edge {
    int u,v,w,fg;
    bool operator < (const edge &b) const {
        return w < b.w;
    }
} e[N*N];

int n,t1,t2,t3,c[N],k[N],x[N],y[N],ind,ans,cnt1,cnt2,fa[N];

int find(int p) {
    return fa[p]==p?p:fa[p]=find(fa[p]);
}

void merge(int p,int q) {
    p=find(p); q=find(q);
    if(p-q) fa[p]=q;
}

signed main() {
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++) {
        cin>>x[i]>>y[i];
    }
    for(int i=1;i<=n;i++) cin>>c[i];
    for(int i=1;i<=n;i++) cin>>k[i];
    for(int i=1;i<=n;i++) {
        for(int j=1;j<i;j++) {
            e[++ind]={i,j,(k[i]+k[j])*(abs(x[i]-x[j])+abs(y[i]-y[j])),0};
        }
    }
    for(int i=1;i<=n;i++) {
        e[++ind]={0,i,c[i],0};
    }
    for(int i=1;i<=n;i++) fa[i]=i;
    sort(e+1,e+ind+1);
    for(int i=1;i<=ind;i++) {
        edge &ed=e[i];
        if(find(ed.u)!=find(ed.v)) {
            ans+=ed.w;
            ed.fg=1;
            merge(ed.u,ed.v);
        }
    }
    for(int i=1;i<=ind;i++) {
        edge &ed=e[i];
        if(ed.fg) {
            if(ed.u==0) {
                ++cnt1;
            }
            if(ed.v==0) {
                ++cnt1;
            }
            if(ed.u && ed.v) {
                ++cnt2;
            }
        }
    }
    cout<<ans<<endl;
    cout<<cnt1<<endl;
    for(int i=1;i<=ind;i++) {
        edge &ed=e[i];
        if(ed.fg) {
            if(ed.u==0) {
                cout<<ed.v<<" ";
            }
            if(ed.v==0) {
                cout<<ed.u<<" ";
            }
        }
    }
    cout<<endl;
    cout<<cnt2<<endl;
    for(int i=1;i<=ind;i++) {
        edge &ed=e[i];
        if(ed.fg) {
            if(ed.u && ed.v) {
                cout<<ed.u<<" "<<ed.v<<endl;
            }
        }
    }
}

相关文章: