codeforces 1245D(最小生成树)

题面链接:https://codeforces.com/problemset/problem/1245/D

题意大概是给你一些城市的坐标,可以在城市中建立发电站,也可以让某个城市和已经建好发电站的城市连接,保证在这两种操作下使得所有的城市供电,在城市建发电站需要花费Ci,城市a和城市b连接需要花费(|Xa-Xb| + |Ya-Yb| )*(Ka+Kb),求最小的花费让所有城市通电。

思路:首先建立一个源点,连接各个城市,边权就是建发电站费用Ci,若选择此边则表示是在该城市建了发电站。

           剩下的城市互相按照题意要求建边,建完全图。

           最终模型就抽象成求最小生成树,用克鲁斯卡尔算法跑一下即可

AC代码:

#include<iostream>
#include<vector>
#include<set>
#include<cstdio> 
#include<algorithm>
#define maxn 2005
using namespace std;
typedef long long ll;
struct node{
	int from,to;
	ll cost;
}e[maxn*maxn];//存储边的信息 
int father[maxn];
int cnt,N,city;
vector<int> sta;//存建发电站的城市 
vector<int> citya,cityb;//存储a b城市表示ab之间有电线 
bool cmp(node a,node b){//比较函数 
	return a.cost < b.cost ;
}
void init(){//初始化 
	cnt = 0;
	for(int i = 0;i<=N;i++){
		father[i] = i;
	}
}
int find(int x){//寻找根 
	if(x == father[x]) return x;
	return father[x] = find(father[x]);
}
bool same(int x,int y){//判断是否在一个集合 
	return find(x)==find(y);
}
void unionSet(int x,int y){ //并查集合并 
	int u = find(x),v = find(y);
	if(u==v) return ;
	father[u] = v;
}
long long kruskal(){ //求最小生成树 
	ll res = 0;
	std::sort(e,e+cnt,cmp);
	for(int i = 0;i<cnt;i++){
		if(same(e[i].from,e[i].to )) continue;
		unionSet(e[i].from ,e[i].to );
		if(e[i].from == 0 || e[i].to == 0){//判一下是否在城市建了发电站(利用源点判断) 
			if(e[i].from == 0) sta.push_back(e[i].to ); 
			else sta.push_back(e[i].from); 
		}
		else{//如果不是,存一些a,b两座连接的城市 
			citya.push_back(e[i].from ),cityb.push_back(e[i].to);  
		}
		res+=e[i].cost ;
	}
	return res; 
}
void addedge(int u,int v,ll C){ //建边操作 
	e[cnt].from = u,e[cnt].to = v,e[cnt].cost = C;
	cnt++;
}
int main(){
	cin>>N;
	init(); 
	vector<long long> vx,vy;
	vector<long long> c,k;
	for(int i = 0;i<N;i++){
		int x,y;cin>>x>>y;
		vx.push_back(x),vy.push_back(y);  
	}
	for(int i = 0;i<N;i++){
		ll tc;cin>>tc;
		c.push_back(tc); 
	}
	for(int i = 0;i<N;i++){
		ll tk;cin>>tk;
		k.push_back(tk); 
	}
	for(int i = 0;i<N;i++){//建立源点,和各个城市连接 
		addedge(0,i+1,c[i]);
	}
	for(int i = 0;i<N;i++){//城市和城市之间建完全图 
		for(int j = i+1;j<N;j++){
			ll c = (abs(vx[i]-vx[j])+abs(vy[i]-vy[j]))*(k[i]+k[j]);
			addedge(i+1,j+1,c);
		}
	}
	ll ans = kruskal();
	cout<<ans<<endl;
	cout<<sta.size()<<endl;
	for(int i = 0;i<sta.size();i++){
		if(i==0) cout<<sta[i];
		else cout<<" "<<sta[i];
	}
	cout<<endl;
	cout<<citya.size()<<endl;
	for(int i = 0;i<citya.size() ;i++){
		cout<<citya[i]<<" "<<cityb[i]<<endl;
	}
	return 0;
} 

 

posted @ 2019-11-09 00:29  AaronChang  阅读(175)  评论(0编辑  收藏  举报