Week 10 图论

P1636 Einstein学画画 

#include<bits/stdc++.h>
using namespace std;
int a[10001];    
int n,m,ans;
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        int x,y;
        cin>>x>>y;
        a[x]++;
        a[y]++;
    }
    for(int i=1;i<=n;i++)
    {
        if(a[i]%2==1)
              ans++;
    }
    if(ans)
       cout<<ans/2;
    else
       cout<<ans+1;
    return 0;
}

P8654 [蓝桥杯 2017 国 C] 合根植物 

#include<iostream>
using namespace std;

int pa[1000001], n, m, ans;
//标记某个格子是否是数的根节点,用来计算有多少树
bool exist[1000001];

//下面是并查集
void initialize()
{
    for (int i = 1; i <= n * m; i++)
    {
        pa[i] = i;
    }
}

int find(int a)
{
    return pa[a] == a ? a : (pa[a] = find(pa[a]));
}

void merge(int a, int b)
{
    pa[find(a)] = find(b);
}

bool check(int a, int b)
{
    return find(a) == find(b);
}

int main()
{
    cin >> n >> m;
    int k;
    cin >> k;
    //初始化
    initialize();
    for (int i = 0; i < k; i++)
    {
        int a, b;
        cin >> a >> b;
        //合并树
        merge(a, b);
    }
    for (int i = 1; i <= m * n; i++)
    {
        //找到某个格子的植物所在的树的根
        int p = find(i);
        //这个根是第一次找到,就标记已找过,并累加计数
        if (!exist[p])
        {
            exist[p] = true;
            ans++;
        }
    }
    cout << ans << endl;
    return 0;
}

 P3958 [NOIP2017 提高组] 奶酪

 

#include<bits/stdc++.h>
using namespace std;//不加本代码爆零
int f[1001];//并查集
int find(int x){
    if (x!=f[x]) f[x]=find(f[x]);
    return f[x];
}//查找+路径压缩
long long dis(long long x,long long y,long long z,long long x1,long long y1,long long z1){
    return (x-x1)*(x-x1)+(y-y1)*(y-y1)+(z-z1)*(z-z1);
}//两点距离公式,注意这里算的是距离平方。
long long x[100001],y[100001],z[100001];
int f1[100001],f2[100001];
//f1记录与顶面相交的洞的序号
//f2记录与底面相交的洞的序号
int main(){
    int t;
    scanf("%d",&t);
    int n,h; 
    long long r;
    for (int i=1;i<=t;i++){
        scanf("%d%d%lld",&n,&h,&r);//long long不开的话...
        int tot1=0;//记录与顶面相交的洞有几个
        int tot2=0;//记录与底面相交的洞有几个
        for (int j=1;j<=n;j++){
          f[j]=j;  //并查集初始化
         }
        for (int j=1;j<=n;j++){
            scanf("%lld%lld%lld",&x[j],&y[j],&z[j]);//long long不开的话...
            if (z[j]+r>=h){//判断这个点是否与顶面相交
                tot1++;
                f1[tot1]=j;
            }
            if (z[j]-r<=0){//判断这个点是否与底面相交
                tot2++;
                f2[tot2]=j;
            }
            for (int k=1;k<=j;k++){//枚举之前的洞是否与这个洞相交,如果相交则合并集合
            	if ((x[j]-x[k])*(x[j]-x[k])+(y[j]-y[k])*(y[j]-y[k])>4*r*r) continue;
            	//防止爆long long的特判。 
                if (dis(x[j],y[j],z[j],x[k],y[k],z[k])<=4*r*r){
                    int a1=find(j);
                    int a2=find(k);
                    if (a1!=a2) f[a1]=a2;
                }
            }
        }
        int s=0;
        //看看每一个中是否有洞连接上下面
        for (int j=1;j<=tot1;j++){
            for (int k=1;k<=tot2;k++){
                if (find(f1[j])==find(f2[k])){
                    s=1; 
                    break;
                }
            }
            if (s==1) break;
        }
        if (s==1) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    return 0;
} 

 P1119 灾后重建

#include<iostream>
#include<cstdio>
#define N 205
using namespace std;
int n,m;
int a[N];
int f[N][N];//邻接矩阵存边
inline void updata(int k){
	for(int i=0;i<n;i++)
	for(int j=0;j<n;j++)
	if(f[i][j]>f[i][k]+f[j][k])
	f[i][j]=f[j][i]=f[i][k]+f[j][k];//用这个新的更新所有前面的 
	return;
}
int main(){
	cin>>n>>m;
	for(int i=0;i<n;i++)
	scanf("%d",a+i);//依次输入每一个村庄建立完成时需要的时间
	for(int i=0;i<n;i++)
	for(int j=0;j<n;j++){
		f[i][j]=1e9;//初始化为保证它不爆炸范围内的最大值 
	}
	for(int i=0;i<n;i++)
	f[i][i]=0;
	int s1,s2,s3;
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&s1,&s2,&s3);
		f[s1][s2]=f[s2][s1]=s3;//初始化边长 
	}
	int q;
	cin>>q;
	int now=0;
	for(int i=1;i<=q;i++){//处理各询问 
		scanf("%d%d%d",&s1,&s2,&s3);
		while(a[now]<=s3&&now<n){
			updata(now);//依次更新点,使它可以被用来更新其他的点 
			now++;
		}
		if(a[s1]>s3||a[s2]>s3)cout<<-1<<endl;
		else {
			if(f[s1][s2]==1e9)cout<<-1<<endl;
			else cout<<f[s1][s2]<<endl;
		}
	}
	return 0;
} 

P2504 [HAOI2006]聪明的猴子

#include<bits/stdc++.h>
using namespace std;
int n,m,k,ans=0;
double sum=-1;
int a[1000005][3],b[1000005],pre[1000005];//	前面一直RE,开大一点;

struct zzz {
	int x,y;
	double p;
} z[1000005];

int cmp(zzz k,zzz d) {
	return k.p<d.p;
}

int find(int x) {
	if(pre[x]==x)
		return x;
	return pre[x]=find(pre[x]);
}

int main() {
	cin>>m;
	for(int i=1; i<=m; i++) {
		cin>>b[i];
	}
	cin>>n;
	for(int i=1; i<=n; i++) {
		cin>>a[i][1]>>a[i][2];
	}
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=n; j++) {
			if(i!=j) {
				k++;
				z[k].x=i;
				z[k].y=j;
				z[k].p=sqrt((a[i][1]-a[j][1])*(a[i][1]-a[j][1])+(a[i][2]-a[j][2])*(a[i][2]-a[j][2]));
			}
		}
	}	
	int cnt=n;//Kruskal!!!
	sort(z+1,z+k+1,cmp);
	for(int i=1; i<=n; i++) {
		pre[i]=i;
	}
	for(int i=1; i<=k; i++) {
		if(cnt==1)
			break;
		int s1=find(z[i].x),s2=find(z[i].y);
		if(s1!=s2) {
			pre[s1]=s2;
			cnt--;
			sum=z[i].p;
		}
	}
	for(int i=1; i<=m; i++) {//比较
		if(sum<=b[i])
			ans++;
	}
	cout<<ans<<endl;//完美输出
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值