[CSP-S2019 江西] 网格图

Sol
其实就是求最小生成树,但不同的是,这是一个网格图。
拿样例来说

可以对所有横向边升序排列得到2 3 4
再对纵向边升序列排列得到1 2 3
易知横向边的最小值2,及纵向边的最小值1是必须要选的。
选出来后,会得到下图

我们记h代表纵向的点,目前取走了多少个
L代表横向的点,取走了多少个
对于横坐标升序排成2 3 4
纵坐标升序排成1 2 3
我们用两个指针来查找接下来的最小边
发现纵向的2是最小的,并且可以选取了条数为N-H,于是得到下图

加完这一列后,则L++。。。。。这个地方要想清楚,因为这些点即在列上,也是行上。
接下来我们要加的边为横向的边长为3的边,并且此时就只能加一条了,而不能加2条,否则就会成环,不是MST了。

最后加一条纵向的长度为3的边,并且也是只能加1条,得到下图

#include<bits/stdc++.h>
using namespace std;
inline int read()
{ int x=0;
bool f=0;
char c=getchar();
while(!isdigit(c))f|=(c=='-'),c=getchar();
while(isdigit(c))x=x*10+(c&15),c=getchar();
return f?-x:x;
}
int n,m,a[300005],b[300005];
long long ans;//不开long long见祖宗。
int main()
{ n=read(),m=read();
for(register int i=1;i<=n;i++)
a[i]=read();
for(register int i=1;i<=m;i++)
b[i]=read();
sort(a+1,a+n+1);
sort(b+1,b+m+1);
ans=(long long)a[1]*(m-1)+(long long)b[1]*(n-1);
cout<<"ans is "<<ans<<endl;
//首先将最小的一行 和 最小的一列加上。
int cnta=2,cntb=2,h=1,l=1;
//h代表纵向上,共有N个点,目前已加了多少个点
//L代表横向上,共有M个点,目前加了多少个点
while(cnta<=n&&cntb<=m)
//双指针来找最小值
{ if(a[cnta]<=b[cntb]) //加上横向边
{
ans+=(long long)a[cnta]*(m-l);
cout<<"add it1 "<<a[cnta]<<" "<<m-l<<endl;
cout<<"add it1 ans is "<<ans<<endl;
cnta++;
h++; //注意是h++
}
else //加上纵向上的图
{
ans+=(long long)b[cntb]*(n-h);
cout<<"add it2 "<<b[cntb]<<" "<<n-h<<endl;
cout<<"add it2 ans is "<<ans<<endl;
cntb++;
l++; //注意是l++
}
}
printf("%lld\n",ans);
return 0;
}

浙公网安备 33010602011771号