这周趁着网课,做了一部分有关图论的题,重拾记忆的感觉,像Kruskal算法、最短路、并查集得重新再理一遍,有些题目需要自己算然后推出规律,但自己还是推不出,需要看大佬题解。有几个题印象比较深刻,所以就写了一下题解:
1、最短网络
P1546 [USACO3.1]最短网络 Agri-Net - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
首先判断是最短路还是最小生成树,由于要使每个点相互连通,因此是最小生成树,选用Kruskal算法来解。对于一个有n个点的图,删去若干条边,使得整张图为一个只有n-1条边的联通体,即所需光纤的最短方案 ,对于每一条光纤如果未连接时,该条光纤两端的两个农场已经联通,则不选择此条,否则将他们联通,并将该条光纤长计入总和,直到加入n-1条。
inline void kruscal () {
sort(edge+1,edge+1+cnt,comp);
int cnt = 0;
for(int i=1; i < = m; ++i){
int uu = find (edge[i].u);
int vv = find (edge[i].v);
if(uu == vv) continue;
ans += edge[i].w;
fa[uu] = vv;
if( ++cnt == n-1 ) break;
}
}
2、Building Roads S
P2872 [USACO07DEC]Building Roads S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
在一个准备连边的图中已经连好一些边,问使图全部联通所需的最小长度。如果按照无边去做肯定会重复,所以先计算所有点之间的距离,然后将所有给定边的边设为0,之后进行Kruskal算法即可。
int n,m,cnt = 0;
cin>>n>>m;
for(int i = 1;i <= n;i++) {
cin>>x[i]>>y[i];
dis[i] = i;//初始化
}
for(int i = 1;i <= m;i++) {
int x,y;
cin>>x>>y;
a[++cnt] = {x,y,0};//边0
}
for(int i = 1;i <= n;i++) {//计算所有点之间的距离
for(int j = 1;j <= n;j++) {
if(i==j) continue;
double val = cal(i,j);//计算i到j的距离
a[++cnt] = {i,j,val};//添加边
}
}
sort(a+1,a+cnt+1);//排序
double ans = 0;
for(int i = 1;i <= cnt;i++) {
node tmp = a[i];
if(dis[getf(tmp.x)]!=dis[getf(tmp.y)]) {
ans += tmp.z;//加边
dis[getf(tmp.x)] = dis[getf(tmp.y)];
}
}
3、空中都市
P6269 [SHOI2002]空中都市 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
这个题看起来好绕,简单来说的题意就是求在n个点中满足每3个点不两两有边的最多边数。看了一些大佬的题解,这道题刚开始没有头绪,先找找规律:n=0.1.2.3比较简单;n=4,答案为4;n=5,答案为6;n=6,答案为9。大佬的解法——托兰定理:设A为N个点中,向外连线最多的点,设它向外连k条线,则与A相连的点之间不允许连线,而剩余N − 1 − k中的任意一点不可能向外连线数大于k,设这些点连线总数为y,当k=[N/2]时, y≤[N2(N的平方)/4]。然后代码为:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
cout<<n*n/4<<endl;
return 0;
}
被安利了一个综艺《超脑少年团》,是关于一群编程大佬用编程解决一些题目的节目,有时间可以看看。