版权声明:我这么弱的蒟蒻,虽然博文不是很好,但也请标明转发地址喵! https://blog.csdn.net/ACerAndAKer/article/details/82756012
这题写的不明不白的
应该是Kruskal
因为我也没太搞懂咋做
当我在废话就好了
我们对于两个本来就有边的城市,考虑先在哪个城市建房
对于两个城市i,j,我们先在i建房的代价是
,化简一下,可以得到
(某等差数列),然后在建j的代价是
,化简和上面一样
先建j同理,然后我们发现,一个点后面那个**“某等差数列”**会被重复多次,所以我们先算前面的,后面的最后再加上,然后把两种情况取min加到ans里
对于没有边的城市,把上面的情况去掉等差数列,然后取min+两边还没盖房子时的人数和,当边权去做最小生成树
//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lli long long int
using namespace std;
const int M=100;
lli n,m,ans;
char map[M][M];
lli st[M],ed[M],co[M];
int fa[M],siz[M],cnt=1,tot;
struct edge
{
lli fr,to,cos;
bool friend operator < (edge a,edge b)
{return a.cos<b.cos;}
}e[M*M];
inline int read()
{
int x=0;char ch=getchar();
while (ch>'9'||ch<'0') ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline int find(int x)
{
if (fa[x]!=x) return fa[x]=find(fa[x]);
return x;
}
inline void unionn(int x,int y)
{
if (siz[x]<=siz[y]) siz[y]+=siz[x],fa[x]=y;
else siz[x]+=siz[y],fa[y]=x;
return ;
}
inline lli calc(int i,int k)
{
return co[i]*(ed[i]-st[i])*st[k]+co[k]*(ed[k]-st[k])*ed[i];
}
inline void Kru()
{
for (int i=1;i<=tot&&cnt<n;i++)
{
int r1=find(e[i].fr);
int r2=find(e[i].to);
if (r1!=r2)
cnt++,ans+=e[i].cos,unionn(r1,r2);
}
return ;
}
signed main()
{
n=read();
for (int i=1;i<=n;i++) st[i]=read();
for (int i=1;i<=n;i++) ed[i]=read();
for (int i=1;i<=n;i++) co[i]=read();
for (int i=1;i<=n;i++) fa[i]=i,siz[i]=1;
for (int i=1;i<=n;i++) scanf("%s",map[i]+1);
for (int i=1;i<=n;i++)
for (int k=1;k<=n;k++)
if (k>i)
{
if (map[i][k]=='Y')
{
int r1=find(i),r2=find(k);
if (r1!=r2) cnt++,unionn(r1,r2);
ans+=min(calc(i,k),calc(k,i));
}
else
{
e[++tot].fr=i;e[tot].to=k;
e[tot].cos=min(calc(i,k),calc(k,i));
}
}
m=read();
for (int i=1;i<=tot;i++)
e[i].cos+=m*(st[e[i].fr]+st[e[i].to]);
sort(e+1,e+tot+1);Kru();
for (int i=1;i<=n;i++)
ans+=(st[i]-1+ed[i])*(ed[i]-st[i])/2*co[i];
cout<<ans;
return 0;
}