贪心策略,随便找一个点一般为1,每次找到与其最近的点加入树,同时对加入的点记忆化,之后更新每个最近的值并用pre记录前驱,(可以打印边与路径);
变形:
对于下面这种对个点可以做中心(如建立发电站)求最小生成树的,找到0点作为超级点,到每个中心的w即建立发电站的费用,将0点加入,求最小生成树即可。
原题:ACWING,3728
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<set>
#include<string.h>
#include<vector>
#include<set>
#include<cmath>
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define ll long long
#define inf 0x3f3f3f3f
#define x first
#define y second
using namespace std;
const int N=2010;
typedef pair<int,int> PII;
ll dist[N];
int distp[N];
vector<int>ans1;
vector<PII>ans2;
PII a[N];
bool su[N];
int wc[N],wk[N];
int n;
inline ll get_disw(int i,int j)
{
int dx=a[i].x-a[j].x;
int dy=a[i].y-a[j].y;
return (ll)(abs(dx)+abs(dy))*(wk[i]+wk[j]);
}
ll prim()
{
su[0]=true;
dist[0]=0;
ll res=0;
for(int i=1;i<=n;i++)dist[i]=wc[i];
for(int i=0;i<n;i++)
{
int t=-1;
for(int j=1;j<=n;j++)
{
if(!su[j]&&(t==-1||dist[t]>dist[j]))
{
t=j;
}
}
su[t]=true;
res+=dist[t];
if(distp[t]==0)ans1.push_back(t);
else ans2.push_back({distp[t],t});
for(int j=1;j<=n;j++)
{
if(!su[j]&&dist[j]>get_disw(j,t))
{
dist[j]=get_disw(j,t);
distp[j]=t;
}
}
}
return res;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i].x>>a[i].y;
for(int i=1;i<=n;i++)cin>>wc[i];
for(int i=1;i<=n;i++)cin>>wk[i];
ll res=prim();
printf("%lld\n",res);
printf("%d\n",ans1.size());
for(auto m: ans1)printf("%d ",m);
puts("");
printf("%d\n",ans2.size());
for(auto& g: ans2)printf("%d %d\n",g.x,g.y);
return 0;
}