acwing 1140《信息学奥赛一本通》最短网络
#include<bits/stdc++.h>
using namespace std;
#define N 110
typedef long long ll;
ll a[N][N];
ll dist[N];
bool vis[N];
int n;
ll prim(){
int start=1;
ll res=0;
dist[1]=0;
vis[1]=1;
//要先将一号节点加入集合
for( int i=1;i<=n-1;i++){ 注意这里是n-1
for( int j=1;j<=n;j++){
dist[j]=min(dist[j],a[start][j]);
}
int maxx=0x7fffffff;
for( int j=1;j<=n;j++){
if(dist[j]<maxx&&vis[j]==0){
maxx=dist[j];
start=j;
}
}
vis[start]=1;
res+=dist[start];
}
return res;
}
int main(){
cin>>n;
memset(a,-1,sizeof(a));
memset(dist,0x3f,sizeof(dist));
for( int i=1;i<=n;i++){
for( int j=1;j<=n;j++){
cin>>a[i][j];
a[j][i]=a[i][j];
}
}
cout<<prim();
}
acwing 1141局域网 《信息学奥赛一本通》
先计算所有边的和sum再减去最小生成树的和就是答案
本题中,图有可能不连通,再使用最小生成树时,如果下一个点的距离是无穷大,就赋为0,重新开一个树。
#include<bits/stdc++.h>
using namespace std;
#define N 110
#define M 410 这里注意开两倍,是双向边
typedef long long ll;
int w[M],to[M],ne[M],h[N];
int cnt;
int vis[N],dist[N];
int n,k;
void add(int a,int b,int c){
w[cnt]=c;to[cnt]=b;ne[cnt]=h[a];h[a]=cnt++;
}
ll prim(){
int start=1;
vis[1]=1;
dist[1]=0;
ll res=0;
for( int i=1;i<n;i++){
for(int j=h[start];j!=-1;j=ne[j]){
int t=to[j];
dist[t]=min(w[j],dist[t]);
}
int maxx=0x7fffffff;
for( int j=1;j<=n;j++){
if(maxx>dist[j]&&vis[j]==0){
start=j;
maxx=dist[j];
}
}
if(dist[start]==dist[105]){
dist[start]=0;
}
res+=dist[start];
vis[start]=1;
}
return res;
}
int main(){
cin>>n>>k;
memset(dist,0x3f,sizeof(dist));
memset(h,-1,sizeof(h));
ll sum=0;
for( int i=1;i<=k;i++){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
sum+=c;
}
cout<<sum-prim();
}
acwing 1142 《信息学奥赛一本通》 繁忙的都市
二分+最小生成树
城市C是一个非常繁忙的大都市,城市中的道路十分的拥挤,于是市长决定对其中的道路进行改造。
城市C的道路是这样分布的:
城市中有 n 个交叉路口,编号是 1∼n,有些交叉路口之间有道路相连,两个交叉路口之间最多有一条道路相连接。
这些道路是 双向 的,且把所有的交叉路口直接或间接的连接起来了。
每条道路都有一个分值,分值越小表示这个道路越繁忙,越需要进行改造。
但是市政府的资金有限,市长希望进行改造的道路越少越好,于是他提出下面的要求:
1.改造的那些道路能够把所有的交叉路口直接或间接的连通起来。
2.在满足要求1的情况下,改造的道路尽量少。
3.在满足要求1、2的情况下,改造的那些道路中分值最大值尽量小。
作为市规划局的你,应当作出最佳的决策,选择那些道路应当被修建。
输入格式
第一行有两个整数 n,m 表示城市有 n 个交叉路口,m 条道路。
接下来 m 行是对每条道路的描述,每行包含三个整数u,v,c 表示交叉路口 u 和 v 之间有道路相连,分值为 c。
输出格式
两个整数 s,max,表示你选出了几条道路,分值最大的那条道路的分值是多少。
数据范围
1≤n≤300,
1≤m≤8000,
1≤c≤10000
输入样例:
4 5
1 2 3
1 4 5
2 4 7
2 3 6
3 4 8
输出样例:
3 6
看到题目中有最大值最小,所以使用二分法,下面是二分法的设计方法
下面是代码:
#include<bits/stdc++.h>
using namespace std;
#define N 310
int n,m;
int mp[N][N];
int dist[N];
int vis[N];
int check(int bound ){
memset(vis,0,sizeof(vis));
memset(dist,0x3f,sizeof(dist));
int res=0;
dist[1]=0;
vis[1]=1;
int start=1;
for( int j=1;j<n;j++){
for( int i=1;i<=n;i++){
if(mp[start][i]==-1) continue;
int cost;
if(mp[start][i]<=bound) cost=0;
else cost=1;
dist[i]=min( cost , dist[i]);
}
int maxx=0x7fffffff;
for( int i=1;i<=n;i++){
if(vis[i]==0&&dist[i]<maxx){
maxx=dist[i];
start=i;
}
}
vis[start]=1;
res+=dist[start];
}
// cout<<res<<" ";
return res;
}
int main(){
cin>>n>>m;
memset(mp,-1,sizeof(mp));
for( int i=1;i<=m;i++){
int a,b,c;
cin>>a>>b>>c;
mp[a][b]=c;
mp[b][a]=mp[a][b];
}
int l=0;
int r=1e4+1;
while(l<r){
int mid=(l+r)>>1;
if(check(mid)<=0) r=mid;
else l=mid+1;
}
cout<<n-1<<" "<<l<<endl;
}
acwing 1143 《信息学奥赛一本通》联络员
#include<bits/stdc++.h>
using namespace std;
#define N 2010
#define M 20010
typedef long long ll;
int w[M],to[M],ne[M],h[N];
int cnt,m,n;
void add( int a,int b,int c){
w[cnt]=c;to[cnt]=b;ne[cnt]=h[a];h[a]=cnt++;
}
int vis[N];
int dist[N];
ll prim(){
memset(dist,0x3f,sizeof(dist));
ll res=0;
int st=1;
vis[1]=1;
dist[1]=0;
int t=n-1;
while(t--){
for( int i=h[st];i!=-1;i=ne[i]){
int j=to[i];
dist[j]=min(dist[j],w[i]);
}
int maxx=0x7fffffff;
for( int i=1;i<=n;i++){
if(dist[i]<maxx&&vis[i]==0){
maxx=dist[i];
st=i;
}
}
vis[st]=1;
res+=dist[st];
}
return res;
}
int main(){
cin>>n>>m;
ll sum=0;//表示必选边的权重和
memset(h,-1,sizeof(h));
for( int i=1;i<=m;i++){
int a,b,c,p;
cin>>p>>a>>b>>c;
if(p==1){
add(a,b,0);
add(b,a,0);
sum+=c;
}
else {
add(a,b,c);
add(b,a,c);
}
}
cout<<sum+prim();
return 0;
}
acwing 1144 /《信息学奥赛一本通》连接格点