zzu2024寒假训练day5(A-H)

文章介绍了如何使用Kruskal算法解决网络连接问题,包括裸Kruskal、考虑已有道路权值、寻找最长路径、优惠价格处理以及拓扑排序的应用。
摘要由CSDN通过智能技术生成

题目链接

目录

1.A

2.B

3.C

4.D

5.E

6.F

7.G

8.H


本来还有一道i题,但本人比较菜,不会写,所以只有A到H

1.A

这题就是裸的kruskal

#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
const int maxn=1e4+5;
struct wy{int x,y,v;} g[maxn];
int f[maxn],ans,n,cnt,vis[maxn];
int getf(int x){return f[x]==x?x:f[x]=getf(f[x]);}

void kruskal()
{
    for(int i=1;i<=n;i++)f[i]=i;
    cnt=0,ans=0;
    for(int i=1;i<=n*(n-1)/2;i++)
    {
        int tx =getf(g[i].x),ty=getf(g[i].y),v=g[i].v;
        if(tx!=ty)
        {
            f[tx]=ty;//合并两个集合
            vis[i]=1;
            ans+=v;
            if(++cnt==n-1)return;
        }
    }
}
bool cmp(wy a,wy b)
{
    return a.v<b.v;
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    while (1)
    {
        cin>>n;
        if(n==0)break;
        for(int i=1;i<=n*(n-1)/2;i++)
        {
            cin>>g[i].x>>g[i].y>>g[i].v;
        }
        sort(g+1,g+n*(n-1)/2+1,cmp);
        kruskal();
        cout<<ans<<"\n";
    }
    return 0;
}

2.B

这题和上题差不多,因为有一些道路已经建设好了,把它们的权值设为0即可,还有输入要用scanf,我就被卡cin了

#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e4+5;
struct wy{int x,y,v;} g[maxn];
int f[maxn],ans,n,cnt;
int getf(int x){return f[x]==x?x:f[x]=getf(f[x]);}

void kruskal()
{
    for(int i=1;i<=n;i++)f[i]=i;
    cnt=0,ans=0;
    for(int i=1;i<=n*(n-1)/2;i++)
    {
        int tx =getf(g[i].x),ty=getf(g[i].y),v=g[i].v;
        if(tx!=ty)
        {
            f[tx]=ty;//合并两个集合
            ans+=v;
            if(++cnt==n-1)return;
        }
    }
}
bool cmp(wy a,wy b)
{
    return a.v<b.v;
}
signed main()
{
    while (1)
    {
        int status;
        cin>>n;
        if(n==0)break;
        for(int i=1;i<=n*(n-1)/2;i++)
        {
            scanf("%d%d%d%d",&g[i].x,&g[i].y,&g[i].v,&status);
            if(status==1)g[i].v=0;
        }
        sort(g+1,g+n*(n-1)/2+1,cmp);
        kruskal();
        printf("%d\n",ans);
    }
    return 0;
}

3.C

这题也是裸的kruskal,只不过求的是最长的一个权值

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1e4+5;
int f[maxn],ans,cnt,n,m;
struct wy{int x,y,v;} g[maxn];

int getf(int x){return f[x]==x?x:f[x]=getf(f[x]);}

void kruskal()
{
    for(int i=1;i<=n;i++)f[i]=i;
    ans=0,cnt=0;
    for(int i=1;i<=m;i++)
    {
        int tx=getf(g[i].x),ty=getf(g[i].y),v=g[i].v;
        if(tx!=ty)
        {
            f[tx]=ty;
            ans=max(ans,v);
            if(++cnt==n-1) return;
        }
    }
}
bool cmp(wy a ,wy b)
{
    return  a.v<b.v;
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>g[i].x>>g[i].y>>g[i].v;
    }
    sort(g+1,g+1+m,cmp);
    kruskal();
    cout<<ans;
    return 0;
}

4.D

裸的kruskal,求最长的一个权值

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1e4+5;
int f[maxn],ans,cnt,n,m;
struct wy{int x,y,v;} g[maxn];

int getf(int x){return f[x]==x?x:f[x]=getf(f[x]);}

void kruskal()
{
    for(int i=1;i<=n;i++)f[i]=i;
    ans=0,cnt=0;
    for(int i=1;i<=m;i++)
    {
        int tx=getf(g[i].x),ty=getf(g[i].y),v=g[i].v;
        if(tx!=ty)
        {
            f[tx]=ty;
            ans=max(ans,v);
            if(++cnt==n-1) return;
        }
    }
}
bool cmp(wy a ,wy b)
{
    return  a.v<b.v;
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>g[i].x>>g[i].y>>g[i].v;
    }
    sort(g+1,g+1+m,cmp);
    kruskal();
    cout<<n-1<<" "<<ans;
    return 0;
}

5.E

i,j相等的边一定不存在,i,j不相等且kij为0的权值为原价,kij不为0的权值取与原价最小值,然后建图,第一件没有优惠,后面的每条边就是优惠价,所以答案要加n

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=3e5+5;
int f[maxn],ans,cnt,n,m,num=1;
struct wy{int x,y,v;} g[maxn];

int getf(int x){return f[x]==x?x:f[x]=getf(f[x]);}

void kruskal()
{
    for(int i=1;i<=n;i++)f[i]=i;
    ans=0,cnt=0;
    for(int i=1;i<=num;i++)
    {
        int tx=getf(g[i].x),ty=getf(g[i].y),v=g[i].v;
        if(tx!=ty)
        {
            f[tx]=ty;
            ans+=v;
            if(++cnt==m-1) return;
        }
    }
}
bool cmp(wy a ,wy b)
{
    return  a.v<b.v;
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>n>>m;
    int t,flag=1;
    for(int i=1;i<=m;i++)
    {
        for(int j=1;j<=m;j++)
        {
            flag=1;
            g[num].x=i;g[num].y=j;
            cin>>t;
            if(t==0)
            {
                if(i!=j)
                {
                    g[num].v=n;
                }
                else flag=0;
            }
            else g[num].v=min(t,n);
            //cout<<"num=="<<num<<"x=="<<g[num].x<<"y=="<<g[num].y<<"v=="<<g[num].v<<"\n";
            if(flag)num++;
        }
    }
    sort(g+1,g+num,cmp);
    kruskal();
    cout<<ans+n;
    return 0;
}

6.F

这题只要,s和t在一个连通分量里就可以停止kruskal

#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
const int maxn=2e4+5;
struct wy{int x,y,v;} g[maxn];
int f[maxn],ans,n,cnt,m,s,t;
int getf(int x){return f[x]==x?x:f[x]=getf(f[x]);}

void kruskal()
{
    for(int i=1;i<=n;i++)f[i]=i;
    cnt=0,ans=0;
    for(int i=1;i<=n*(n-1)/2;i++)
    {
        int tx =getf(g[i].x),ty=getf(g[i].y),v=g[i].v;
        if(tx!=ty)
        {
            f[tx]=ty;//合并两个集合
            ans=max(ans,v);
            if(getf(s)==getf(t))return;
        }
    }
}
bool cmp(wy a,wy b)
{
    return a.v<b.v;
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
        cin>>n>>m>>s>>t;
        for(int i=1;i<=m;i++)
        {
            cin>>g[i].x>>g[i].y>>g[i].v;
        }
        sort(g+1,g+1+m,cmp);
        kruskal();
        cout<<ans<<"\n";
    return 0;
}

7.G

这题的题意也是有点模糊,纯靠自悟,我们最终是要找输出层的状态,而出度为0的就是输出层

题目最坑的点在于,第一层一定是激活状态,所以第一层的阈值没有用,但题目没有明说,也是无语,

建个图,在次基础上拓扑排序即可.

//拓扑排序,找出入度为0的点,入队,更新拓扑序,遍历队列里的元素,减少后入度为0的入队,更新拓扑序
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e4+400;
int head[N],tot,n,m,vis[N],c[N],u,out[N];
struct wy{int y,v,next;}a[N];//边集数组
queue<int>q;

void add(int x,int y,int v)
{
    a[++tot].y=y;a[tot].v=v;a[tot].next=head[x];head[x]=tot;
}

void topsort()
{
    while (q.size())
    {
        int x=q.front();q.pop();
        if(c[x]<=0)continue;//小于0的直接舍弃
        for(int i=head[x];i;i=a[i].next)
        {
            int y=a[i].y;
            c[y]+=a[i].v*c[x];
            if(!vis[y])
            {
                q.push(y);
                vis[y]=1;
            }
        }
    }
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>n>>m;
    
    for(int i=1;i<=n;i++)
    {
        vis[i]=out[i]=0;
        cin>>c[i]>>u;//输入状态和阈值
        if(c[i]>0)
        {
            q.push(i);
            vis[i]=1;
        }
        else
        c[i]-=u;//?
    }
    for(int i=1;i<=m;i++)
    {
        int x,y,v;
        cin>>x>>y>>v;
        add(x,y,v);//加边
        out[x]=1;//无出度的为输出层
    }
    topsort();
    int flag=0;
    for(int i=1;i<=n;i++)
    {
        if(!out[i]&&c[i]>0)
        {
            cout<<i<<" "<<c[i]<<'\n';
            flag=1;
        }
    }
    if(!flag)
    cout<<"NULL";
    return 0;
}

8.H

这题就是未停靠站的等级一定比停靠站低,所以可以建立从未停靠站到停靠站的边,然后拓扑排序,计数即可,就是实现细节有点繁琐

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1e6+5;
int n,m,tot,du[maxn],head[maxn],ans=0,s,start,ed,t,dep[1005];
bool found[1005],num[1005];
bool vis[1005][1005];
struct wy{int y,next;}a[maxn];

void add(int x,int y)
{
    a[++tot].y=y;a[tot].next=head[x];head[x]=tot;
}

void topsort()
{
    queue<int>q;
    for(int i=1;i<=n;i++)
    {
        if(du[i]==0&&num[i]==1)
        {
            q.push(i);
        }
    }
    while(!q.empty())
    {
        int si=q.size();
        ans++;
        for(int j=1;j<=si;j++)
        {
        int x=q.front();q.pop();
        for(int i=head[x];i;i=a[i].next)
        {
            int y=a[i].y;
            if(--du[y]==0)
            {
                q.push(y);
            }
        }
        }
    }
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>s;
        int cnt=0;
        vector<int>choose(1005);
        memset(found,0,sizeof(found));
        for(int j=1;j<=s;j++)
        {
            cin>>choose[cnt];
            if(j==1)start=choose[cnt];
            if(j==s)ed=choose[cnt];
            found[choose[cnt]]=1;
            cnt++;
        }//读入数据
        if(ed-start==1)continue;
        for(int k=start;k<=ed;k++)
        {
            if(!found[k])
            {
                for(int l=0;l<cnt;l++)
                {
                    if(!vis[k][choose[l]])
                    {
                        add(k,choose[l]);
                        num[k]=1;
                        num[choose[l]]=1;
                        du[choose[l]]++;
                        vis[k][choose[l]]=1;
                        //cout<<"u=="<<k<<"v=="<<choose[l]<<"\n";
                    }
                }
            }
        }
    }
    topsort();
    cout<<ans;   
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值