没有做过这种题目,所以当时就没有做出来,其实即使建立一个超级源点,和每个点相连,以建发电站的费用为边权,其他的点之间的边权就按题目给的算。然后跑一遍最小生成树即可,我用的是prim。注意数据范围(>_<),因为这个一直WA。
#include <bits/stdc++.h>//注意数据范围long long
using namespace std;
const int N=2e3+5;
const int inf=0x3f3f3f3f;
typedef long long ll;
ll pic[N][N];
int x[N],y[N],c[N],k[N],pre[N];
ll dis[N];
bool vis[N];
struct node
{
int id;
ll d;
int pre;
friend bool operator <(node a,node b)
{
return a.d>b.d;
}
};
priority_queue<node>que;
vector<pair<int,int> >res[2];
ll prim(int n)
{
ll ans=0;
for(int i=0;i<=n;i++)
{
dis[i]=inf;
vis[i]=0;
pre[i]=i;
}
dis[0]=0;
while(!que.empty())
que.pop();
que.push({0,0,0});
while(!que.empty())
{
node now=que.top();
que.pop();
if(vis[now.id])
continue;
for(int i=0;i<=n;i++)
{
if(i!=now.id)
{
if(dis[i]>pic[now.id][i])
{
dis[i]=pic[now.id][i];
if(!vis[i])
que.push({i,dis[i],now.id});
}
}
}
vis[now.id]=1;
ans+=now.d;
pre[now.id]=now.pre;
}
return ans;
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
res[0].clear();
res[1].clear();
for(int i=1;i<=n;i++)
scanf("%d%d",&x[i],&y[i]);
for(int i=1;i<=n;i++)
scanf("%d",&c[i]);
for(int i=1;i<=n;i++)
scanf("%d",&k[i]);
for(int i=1;i<=n;i++)
{
pic[0][i]=c[i];
pic[i][0]=c[i];
for(int j=1;j<=n;j++)
pic[i][j]=(ll)(k[i]+k[j])*(abs(x[i]-x[j])+abs(y[i]-y[j]));//没有进行强制类型转换,WA了6发
}
printf("%lld\n",prim(n));
for(int i=1;i<=n;i++)
{
if(pre[i]==0)
res[0].push_back({0,i});
else
res[1].push_back({pre[i],i});
}
printf("%d\n",res[0].size());
for(int i=0;i<res[0].size();i++)
printf("%d%c",res[0][i].second,i==res[0].size()-1?'\n':' ');
printf("%d\n",res[1].size());
for(int i=0;i<res[1].size();i++)
printf("%d %d\n",res[1][i].first,res[1][i].second);
}
return 0;
}