思路:
这题一共有两种思路:
1.设立一个虚点,将所有点和它连接,cost
是ci
,然后其它点两两相连,cost
为两点之间建立连接所需价格,然后求这个图的最小生成树,求出来的树中,和虚点相连的点就是自己设发电站的点,两个顶点都不是虚点的边就是需要修路的边;(在求解过程中需要使用long long
)
2.由贪心思想可以得知,所有ci
中最小的那个i
点一定要设立发电站,此时我们遍历所有j>=1&&j<=n&&j!=i
,这时j
有两种选择:(1)和i
相连 (2)自己建发电站;我们在这两种里面选择花费最小的那一种并更新cj
,并记录更小的情况是自己建站还是和i
连接(只是更新cj
,还未决定到底是自己建or连接i
or连接其它点),全部更新一遍之后,我们再在所有未建发电站的点里选取c
最小的那一个,对它通电(是自己建站还是进行连接,就根据之前的记录),然后依次循环到所有点通电就ok了~(因为笔者只实现了最小生成树,这种贪心方法没有贴出代码,所以我就稍微啰嗦一点了QAQ)
代码:
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> P;
typedef long long LL;
#define fi first
#define sc second
#define pb(a) push_back(a)
#define mp(a,b) make_pair(a,b)
#define rp(i,n) for(int i=0;i<n;i++)
#define rpn(i,n) for(int i=1;i<=n;i++)
const int MAX_N=2000+99;
int par[MAX_N],rank_u[MAX_N]; //MAX_N集合里最多元素个数
void init_union(int n){
for(int i=0;i<n;i++){
par[i]=i;
rank_u[i]=0;
}
}
int find(int x){
if(par[x]==x) return x;
else return par[x]=find(par[x]);
}
void unite(int x,int y){
x=find(x);
y=find(y);
if(x==y) return;
if(rank_u[x]<rank_u[y]) par[x]=y;
else{
par[y]=x;
if(rank_u[x]==rank_u[y]) rank_u[x]++;
}
}
bool same(int x,int y){
return find(x)==find(y);
}
struct edge{int u,v;LL cost;};
bool cmp(const edge& e1,const edge& e2){
return e1.cost<e2.cost;
}
const int MAX_E=2001000+99;
edge es[MAX_E];
int V,E;//顶点数和边数
vector<int> v1;//自己建发电站
vector<P> v2;//连接别的发电站
LL kruskal(){
sort(es,es+E,cmp);
init_union(V);
LL res=0;
for(int i=0;i<E;i++){
edge e=es[i];
if(!same(e.u,e.v)){
if(e.u&&e.v) v2.pb(mp(e.u,e.v));
else v1.pb(e.u?e.u:e.v);
unite(e.u,e.v);
res+=e.cost;
}
}
return res;
}
P cod[MAX_N];
LL K[MAX_N];
LL cost(int a,int b){return (K[a]+K[b])*(abs(cod[a].fi-cod[b].fi)+abs(cod[a].sc-cod[b].sc));}
int main(){
IOS;
int n;
cin>>n;
V=n+1; E=(n+1)*n/2;
rpn(i,n) cin>>cod[i].fi>>cod[i].sc;
int pos=0;
rpn(i,n){
LL cost;
cin>>cost;
es[pos++]=edge{0,i,cost};
}
rpn(i,n) cin>>K[i];
for(int i=1;i<n;i++){
for(int j=i+1;j<=n;j++) es[pos++]=edge{i,j,cost(i,j)};
}
cout<<kruskal()<<'\n';
cout<<v1.size()<<'\n'<<v1[0];
for(int i=1;i<v1.size();i++) cout<<' '<<v1[i];
cout<<'\n'<<v2.size()<<'\n';
rp(i,v2.size()) cout<<v2[i].fi<<' '<<v2[i].sc<<'\n';
return 0;
}