目录
本来还有一道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;
}