题目大意
农夫FJ的奶牛们有空旷恐惧症,所以,FJ打算在他的农场围上篱笆。他的农场是一个矩形区域。左上角的坐标是(0,0),右下角的坐标是(A,B),FJ修建了n(0<=n<=2000)个竖直的篱笆,其横坐标分别为a1,a2,a3,……,an,其中0
分析
可以轻易地看出这道题是要求最小生成树,处理出连通块之间栅栏的长度然后做最小生成树即可。
但是这样会Time Limited Exceed,尽管算法时间复杂度为
O(n2log2n)
我们进行一些优化:由于每一行或每一列中的相邻两个连通块之间的栅栏长度相等,我们可以考虑使用kruskal算法,仅仅对每两个栅栏之间的距离排序,然后然后再对这一行(列)的所有相邻连通块连边即可。
算法时间复杂度还是
O(n2log2n)
还要注意常数优化。
代码
#include<cstdio>
#include<algorithm>
#define MAXN 2000
using namespace std;
long long ans;
int n,a[MAXN+10],b[MAXN+10],A,B,m,tot,fa[(MAXN+1)*(MAXN+1)+10];
void Read(int &x){
char c;
while(c=getchar(),c!=EOF)
if(c>='0'&&c<='9'){
x=c-'0';
while(c=getchar(),c>='0'&&c<='9')
x=x*10+c-'0';
ungetc(c,stdin);
return;
}
}
void read(){
int i,t;
Read(A),Read(B),Read(n),Read(m);
for(i=1;i<=n;i++)
Read(a[i]);
for(i=1;i<=m;i++)
Read(b[i]);
sort(a+1,a+n+1);
sort(b+1,b+m+1);
a[++n]=A;
b[++m]=B;
for(i=n;i;i--)
a[i]-=a[i-1];
for(i=m;i;i--)
b[i]-=b[i-1];
sort(a+1,a+n+1);
sort(b+1,b+m+1);
t=n*m;
for(i=1;i<=t;i++)
fa[i]=i;
}
int find(int x){
return x==fa[x]?x:fa[x]=find(fa[x]);
}
void kruskal(){
int i,j,k,l;
i=j=1;
while(i<=n||j<=m){
if(j>m||(i<=n&&a[i]<=b[j])){
k=(i-1)*m+1;
for(l=1;l<m;l++,k++)
if(find(k)!=find(k+1))
fa[fa[k]]=fa[k+1],ans+=a[i];
++i;
}
else{
k=j;
for(l=1;l<n;l++,k+=m)
if(find(k)!=find(k+m))
fa[fa[k]]=fa[k+m],ans+=b[j];
++j;
}
}
}
int main()
{
read();
kruskal();
printf("%lld\n",ans);
}