Shichikuji and Power Grid
題意還是很簡單,每個點有點權,每個點之間也有邊權
求最小生成森林,每個一顆最小生成樹的權值等於邊權+最小點權
思路
邊權我們很好處理,有模板,但如何處理這個點權,便成了主要的問題
如果我們以邊權的思路思考點權,那麼點權就是某個點從到該點的邊權
而我們可以假設0點為這個“某個點”,向每個點建邊,那麼最終求得的最小生成森林就會因為這個0點,連成一個最小生成樹
最後建好邊,套模板就可以了
CODE
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define x first
#define y second
typedef pair<int,int> pii;
typedef pair<ll,ll>pll;
const int maxn=2e3+10;
int cnt=0;
int head[maxn];
struct node{
int u,v;
ll w;
}e[maxn*maxn];
int c[maxn];
int n;
int k[maxn];
pii p[maxn];
int f[maxn];
vector<int> powerst;
vector<pii> edge;
ll val(int i,int j){
return (ll)(k[i]+k[j])*(abs(p[i].x-p[j].x)+abs(p[i].y-p[j].y)) ;
}
int find(int x){
if(x!=f[x]) return f[x]=find(f[x]);
return x;
}
void init(){
cin>>n;
for(int i=1;i<=n;++i) cin>>p[i].x>>p[i].y;
for(int i=1;i<=n;++i) cin>>c[i],f[i]=i;
for(int i=1;i<=n;++i) cin>>k[i];
//0點
for(int i=1;i<=n;++i) {
e[++cnt].u=0;
e[cnt].v=i;
e[cnt].w=c[i];
}
//建邊
for(int i=1;i<=n;++i)
for(int j=i+1;j<=n;++j){
e[++cnt].u=i;
e[cnt].v=j;
e[cnt].w=val(i,j);
}
}
bool cmp(node a,node b){
return a.w<b.w;
}
ll cost=0;
void krus(){
sort(e+1,e+1+cnt,cmp);
int tot=0;
for(int i=1;i<=cnt;++i){
int u=find(e[i].u);
int v=find(e[i].v);
if(u!=v){
if(e[i].u==0) powerst.push_back(e[i].v);
else {
edge.push_back(make_pair(e[i].u,e[i].v));
}
f[u]=v;
cost+=e[i].w;
if(++tot==n) break;
}
}
}
void print(){
cout<<cost<<endl;
cout<<powerst.size()<<endl;
if(!powerst.empty())
for(auto x:powerst){
cout<<x<<" ";
}
cout<<endl;
cout<<edge.size()<<endl;
if(!edge.empty())
for(auto t:edge){l
cout<<t.x<<" "<<t.y<<endl;
}
}
int main(){
cin.tie(0);cout.tie(0);
init();
krus();
print();
return 0;
}
小結
這個題關鍵的是轉化點權的思路:點權化為邊權
這個思路學會了,可能會在以後的題中可以應用