1、早上
首先看了一遍啊哈算法上的最小生成树,然后开始做本周的题目,做了两个。(3h)
(1)P3366 【模板】最小生成树
#include <bits/stdc++.h>
using namespace std;
#define M 200010
#define N 5010
int n,m,fa[N],cnt=0,sum=0;
struct tree{
int fir;
int nxt;
int w;
}p[M];
bool cmp(struct tree a,struct tree b){//按边的权值升序排列
if(a.w<b.w) return true;
else return false;
}
int find(int t){//找父亲
if(fa[t]==t) return t;
return fa[t]=find(fa[t]);//压缩路径
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)//初始化父亲
fa[i]=i;
for(int i=1;i<=m;i++)
scanf("%d%d%d",&p[i].fir,&p[i].nxt,&p[i].w);
sort(p+1,p+m+1,cmp);
for(int i=1;i<=m;i++){
int fa1=find(p[i].fir),fa2=find(p[i].nxt);
if(fa1==fa2) continue;//两点在一个并查集内,就会组成环
sum+=p[i].w;
cnt++;
fa[fa1]=fa2;//已连接,所以要合并集合
if(cnt==n-1) break;
}
if(cnt==n-1)//n个点能连n-1条边即可
printf("%d\n",sum);
else
printf("orz\n");
}
(2)P1195 口袋的天空
#include <bits/stdc++.h>
using namespace std;
#define M 10010
int fa[1010],sum,cnt;
struct tree{
int u;
int v;
int w;
}e[M];
bool cmp(struct tree a,struct tree b){//按边的权值升序排列
if(a.w<b.w) return true;
else return false;
}
int find(int t){//找父亲
if(fa[t]==t) return t;
return fa[t]=find(fa[t]);//压缩路径
}
int main(){
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)//初始化父亲
fa[i]=i;
for(int i=1;i<=m;i++)
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
sort(e+1,e+m+1,cmp);
for(int i=1;i<=m;i++){
int fa1=find(e[i].u),fa2=find(e[i].v);
if(fa1==fa2) continue;//两点在一个并查集内,就会组成环
sum+=e[i].w;
cnt++;
fa[fa1]=fa2;//已连接,所以要合并集合
if(cnt==n-k) break;
}
if(cnt==n-k)//n朵云朵要组成k个棉花糖,则需要连接n-k根线
printf("%d\n",sum);
else
printf("No Answer\n");
}
2、下午
继续做本周的最短路径题目,做出了剩下的三个(4h)。
(1) P2121 拆地毯
#include <bits/stdc++.h>
using namespace std;
#define N 100010
int n,m,k,fa[N],cnt=0,sum=0;
struct tree{
int u;
int v;
int w;
}e[N];
bool cmp(struct tree a,struct tree b){//按边的权值升序排列
if(a.w>b.w) return true;
else return false;
}
int find(int t){//找父亲
if(fa[t]==t) return t;
return fa[t]=find(fa[t]);//压缩路径
}
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)//初始化父亲
fa[i]=i;
for(int i=1;i<=m;i++)
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
sort(e+1,e+m+1,cmp);
for(int i=1;i<=m;i++){
int fa1=find(e[i].u),fa2=find(e[i].v);
if(fa1==fa2) continue;//两点在一个并查集内,就会组成环
sum+=e[i].w;
cnt++;
fa[fa1]=fa2;//已连接,所以要合并集合
if(cnt==k) break;
}
printf("%d\n",sum);
}
(2)P1991 无线通讯网
#include <bits/stdc++.h>
using namespace std;
int fa[510];
struct tree{
int u;
int v;
double w;
}e[1000001];
bool cmp(struct tree a,struct tree b){//按边的权值升序排列
if(a.w<b.w) return true;
else return false;
}
int find(int t){//找父亲
if(fa[t]==t) return t;
return fa[t]=find(fa[t]);//压缩路径
}
int main(){
int s,p,zb[510][2],k=1,cnt=0;
double ans;
scanf("%d%d",&s,&p);
for(int i=1;i<=p;i++)
fa[i]=i;
for(int i=1;i<=p;i++)
scanf("%d%d",&zb[i][0],&zb[i][1]);
for(int i=1;i<=p;i++)//求出所有哨塔,两两之间的距离
for(int j=i+1;j<=p;j++){
e[k].u=i;
e[k].v=j;
e[k++].w=sqrt((zb[i][0]-zb[j][0])*(zb[i][0]-zb[j][0])+(zb[i][1]-zb[j][1])*(zb[i][1]-zb[j][1]));
}
sort(e+1,e+k+1,cmp);
for(int i=1;i<=k;i++){
int fa1=find(e[i].u),fa2=find(e[i].v);
if(fa1==fa2) continue;//两点在一个并查集内,就会组成环
ans=e[i].w;
cnt++;
fa[fa1]=fa2;//已连接,所以要合并集合
if(cnt==p-1-(s-1)) break;//s个卫星电话可连接s-1线,找到所有需要连接无线电哨塔的数量-卫星电话已连接数量,即可停止
}
printf("%.2lf",ans);
}
(3)P2872 [USACO07DEC]Building Roads S
#include <bits/stdc++.h>
using namespace std;
int fa[1010];
struct tree{
int u;
int v;
double w;
}e[5000100];
bool cmp(struct tree a,struct tree b){//按边的权值升序排列
if(a.w<b.w) return true;
else return false;
}
int find(int t){//找父亲
if(fa[t]==t) return t;
return fa[t]=find(fa[t]);//压缩路径
}
int main(){
int n,m,zb[1000][2],k=1,cnt=0;
double sum=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=1;i<=n;i++)
scanf("%d%d",&zb[i][0],&zb[i][1]);
while(m--){
int u,v;
scanf("%d%d",&u,&v);
fa[find(u)]=find(v);//合并
}
for(int i=1;i<=n;i++)//求出所有点,两两之间的距离
for(int j=i+1;j<=n;j++){
e[k].u=i;
e[k].v=j;
e[k++].w=sqrt((double)(zb[i][0]-zb[j][0])*(zb[i][0]-zb[j][0])+(double)(zb[i][1]-zb[j][1])*(zb[i][1]-zb[j][1]));
}
sort(e+1,e+k+1,cmp);
for(int i=1;i<=k;i++){
int fa1=find(e[i].u),fa2=find(e[i].v);
if(fa1==fa2) continue;//两点在一个并查集内,就会组成环
sum+=e[i].w;
cnt++;
fa[fa1]=fa2;//已连接,所以要合并集合
if(cnt==n-1-m) break;//m条边已确定,所以减去
}
printf("%.2lf",sum);
}
3、晚上
首先过了一遍今天的题目和代码,然后把昨天学的最短路的疑点又看了看。(1h)
今日总共学习时长8h。