目录
1 1141 局域网
某个局域网内有 n台计算机和 k 条 双向 网线,计算机的编号是 1∼n。由于搭建局域网时工作人员的疏忽,现在局域网内的连接形成了回路,我们知道如果局域网形成回路那么数据将不停的在回路内传输,造成网络卡的现象。
注意:
- 对于某一个连接,虽然它是双向的,但我们不将其当做回路。本题中所描述的回路至少要包含两条不同的连接。
- 两台计算机之间最多只会存在一条连接。
- 不存在一条连接,它所连接的两端是同一台计算机。
因为连接计算机的网线本身不同,所以有一些连线不是很畅通,我们用 f(i,j) 表示 i,j 之间连接的畅通程度,f(i,j) 值越小表示 i,j 之间连接越通畅。
现在我们需要解决回路问题,我们将除去一些连线,使得网络中没有回路且不影响连通性(即如果之前某两个点是连通的,去完之后也必须是连通的),并且被除去网线的 Σf(i,j) 最大,请求出这个最大值。
输入格式
第一行两个正整数 n,k
接下来的 k 行每行三个正整数 i,j,m 表示 i,j 两台计算机之间有网线联通,通畅程度为 m。
输出格式
一个正整数,表示被除去网线的 Σf(i,j) 的最大值。
数据范围
1≤n≤100
0≤k≤200
1≤f(i,j)≤1000
输入样例:
5 5
1 2 8
1 3 1
1 5 3
2 4 5
3 4 2
输出样例:
8
#include<bits/stdc++.h>
using namespace std;
int p[210];
struct T{
int a,b,w;
}e[210];
int find(int x)
{
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
bool cmp(T a,T b)
{
return a.w<b.w;
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++)p[i]=i;
for(int i=0;i<m;i++)
{
int a,b,w;
cin>>a>>b>>w;
e[i]={a,b,w};
}
sort(e,e+m,cmp);
int ans=0;
for(int i=0;i<m;i++){
int a=find(e[i].a),b=find(e[i].b),w=e[i].w;
if(a!=b)p[a]=b;
else ans+=w;
}
cout<<ans;
return 0;
}
2 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;
int p[310];
struct T{
int a,b,w;
}s[10010];
bool cmp(T a,T b)
{
return a.w<b.w;
}
int find (int x)
{
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)p[i]=i;
for(int i=0;i<m;i++){
int a,b,w;
cin>>a>>b>>w;
s[i]={a,b,w};
}
sort(s,s+m,cmp);
int ans;
for(int i=0;i<m;i++){
int a=find(s[i].a),b=find(s[i].b),w=s[i].w;
if(a!=b){
p[a]=b;
ans=w;
}
}
cout<<n-1<<" "<<ans;
return 0;
}
3 1143 联络员
Tyvj已经一岁了,网站也由最初的几个用户增加到了上万个用户,随着Tyvj网站的逐步壮大,管理员的数目也越来越多,现在你身为Tyvj管理层的联络员,希望你找到一些通信渠道,使得管理员两两都可以联络(直接或者是间接都可以)。本题中所涉及的通信渠道都是 双向 的。
Tyvj是一个公益性的网站,没有过多的利润,所以你要尽可能的使费用少才可以。
目前你已经知道,Tyvj的通信渠道分为两大类,一类是必选通信渠道,无论价格多少,你都需要把所有的都选择上;还有一类是选择性的通信渠道,你可以从中挑选一些作为最终管理员联络的通信渠道。
数据保证给出的通信渠道可以让所有的管理员联通。
注意: 对于某两个管理员 u,v,他们之间可能存在多条通信渠道,你的程序应该累加所有 u,v 之间的必选通行渠道。
输入格式
第一行两个整数 n,m 表示Tyvj一共有 n 个管理员,有 m 个通信渠道;
第二行到 m+1 行,每行四个非负整数,p,u,v,w 当 p=1 时,表示这个通信渠道为必选通信渠道;当 p=2 时,表示这个通信渠道为选择性通信渠道;u,v,w 表示本条信息描述的是 u,v 管理员之间的通信渠道,u 可以收到 v 的信息,v 也可以收到 u 的信息,w 表示费用。
输出格式
一个整数,表示最小的通信费用。
数据范围
1≤n≤2000
1≤m≤10000
输入样例:
5 6
1 1 2 1
1 2 3 1
1 3 4 1
1 4 1 1
2 2 5 10
2 2 5 5
输出样例:
9
#include<bits/stdc++.h>
using namespace std;
int p[2010];
struct T{
int a,b,w;
}s[10010];
bool cmp(T a,T b)
{
return a.w<b.w;
}
int find(int x)
{
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
int main()
{
int n,m;
int ans=0;
cin>>n>>m;
for(int i=1;i<=n;i++)p[i]=i;
int k=0;
while(m--){
int t,a,b,c;
cin>>t>>a>>b>>c;
if(t==1){
p[find(a)]=find(b);
ans+=c;
}else{
s[k++]={a,b,c};
}
}
sort(s,s+k,cmp);
for(int i=0;i<k;i++){
int a=find(s[i].a),b=find(s[i].b),w=s[i].w;
if(a!=b){
p[a]=b;
ans+=w;
}
}
cout<<ans;
return 0;
}
4 1144 连接格点
有一个 m 行 n 列的点阵,相邻两点可以相连。
一条纵向的连线花费一个单位,一条横向的连线花费两个单位。
某些点之间已经有连线了,试问至少还需要花费多少个单位才能使所有的点全部连通。
输入格式
第一行输入两个正整数 m 和 n。
以下若干行每行四个正整数 x1,y1,x2,y2,表示第 x1行第 y1 列的点和第 x2 行第 y2 列的点已经有连线。
输入保证|x1−x2|+|y1−y2|=1
输出格式
输出使得连通所有点还需要的最小花费。
数据范围
1≤m,n≤1000
0≤已经存在的连线数≤10000
输入样例:
2 2
1 1 2 1
输出样例:
3
#include<bits/stdc++.h>
using namespace std;
const int N=1010,M=N*N,K=2*M;
int n,m,k;
int ids[N][N];
struct T{
int a,b,w;
}s[K];
int p[M];
int find (int x)
{
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
void get()
{
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1},dw[4]={1,2,1,2};
for(int z=0;z<2;z++){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int u=0;u<4;u++){
if(u%2==z){
int x=i+dx[u],y=j+dy[u],w=dw[u];
if(x&&x<=n&&y&&y<=m){
int a=ids[i][j],b=ids[x][y];
if(a<b)s[k++]={a,b,w};
}
}
}
}
}
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n*m;i++)p[i]=i;
for(int i=1,t=1;i<=n;i++){
for(int j=1;j<=m;j++,t++){
ids[i][j]=t;
}
}
int x1,y1,x2,y2;
while(cin>>x1>>y1>>x2>>y2){
int a=ids[x1][y1],b=ids[x2][y2];
p[find(a)]=find(b);
}
get();
int ans=0;
for(int i=0;i<k;i++){
int a=find(s[i].a),b=find(s[i].b),w=s[i].w;
if(a!=b){
ans+=w;
p[a]=b;
}
}
cout<<ans;
return 0;
}
5 1145 北极通讯网络
北极的某区域共有 n 座村庄,每座村庄的坐标用一对整数 (x,y) 表示。
为了加强联系,决定在村庄之间建立通讯网络,使每两座村庄之间都可以直接或间接通讯。
通讯工具可以是无线电收发机,也可以是卫星设备。
无线电收发机有多种不同型号,不同型号的无线电收发机有一个不同的参数 d,两座村庄之间的距离如果不超过 d,就可以用该型号的无线电收发机直接通讯,d 值越大的型号价格越贵。现在要先选择某一种型号的无线电收发机,然后统一给所有村庄配备,数量不限,但型号都是 相同的。
配备卫星设备的两座村庄无论相距多远都可以直接通讯,但卫星设备是 有限的,只能给一部分村庄配备。
现在有 k 台卫星设备,请你编一个程序,计算出应该如何分配这 k 台卫星设备,才能使所配备的无线电收发机的 d 值最小。
例如,对于下面三座村庄:
其中,|AB|=10,|BC|=20,|AC|=105√≈22.36
如果没有任何卫星设备或只有 1 台卫星设备 (k=0 或 k=1),则满足条件的最小的 d=20,因为 A 和 B,B 和 C 可以用无线电直接通讯;而 A 和 C 可以用 B 中转实现间接通讯 (即消息从 A 传到 B,再从 B 传到 C);
如果有 2 台卫星设备 (k=2),则可以把这两台设备分别分配给 B 和 C ,这样最小的 d 可取 10,因为 A 和 B 之间可以用无线电直接通讯;B和 C 之间可以用卫星直接通讯;A 和 C 可以用 B 中转实现间接通讯。
如果有 3 台卫星设备,则 A,B,C 两两之间都可以直接用卫星通讯,最小的 d 可取 0。
输入格式
第一行为由空格隔开的两个整数 n,k;
接下来 n 行,每行两个整数,第 i 行的 xi,yi表示第 i 座村庄的坐标 (xi,yi)。
输出格式
一个实数,表示最小的 d 值,结果保留 2 位小数。
数据范围
1≤n≤500
0≤x,y≤104
0≤k≤100
输入样例:
3 2
10 10
10 0
30 0
输出样例:
10.00
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
const int N=510,M=N*N/2;
int n,k,m;
struct T{
int a,b;
double w;
}s[M];
typedef pair<int,int>PII;
PII q[M];
int p[N];
bool cmp(T a,T b)
{
return a.w<b.w;
}
int find(int x)
{
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
double get(PII a,PII b)
{
int x=a.x-b.x,y=a.y-b.y;
return sqrt(x*x+y*y);
}
int main()
{
cin>>n>>k;
for(int i=0;i<n;i++)cin>>q[i].x>>q[i].y;
for(int i=0;i<n;i++){
for(int j=0;j<i;j++){
s[m++]={i,j,get(q[i],q[j])};
}
}
sort(s,s+m,cmp);
for(int i=0;i<n;i++)p[i]=i;
int cnt=n;
double ans=0;
for(int i=0;i<m;i++){
if(cnt<=k)break;
int a=find(s[i].a),b=find(s[i].b);
double w=s[i].w;
if(a!=b){
p[a]=b;
cnt--;
ans=w;
}
}
printf("%.2lf",ans);
return 0;
}
6 1146 新的开始
发展采矿业当然首先得有矿井,小 FF 花了上次探险获得的千分之一的财富请人在岛上挖了 n 口矿井,但他似乎忘记了考虑矿井供电问题。
为了保证电力的供应,小 FF 想到了两种办法:
- 在矿井 i 上建立一个发电站,费用为 vi(发电站的输出功率可以供给任意多个矿井)。
- 将这口矿井 i 与另外的已经有电力供应的矿井 j 之间建立电网,费用为 pi,j
小 FF 希望你帮他想出一个保证所有矿井电力供应的最小花费方案。
输入格式
第一行包含一个整数 n,表示矿井总数。
接下来 n 行,每行一个整数,第 i个数 vi 表示在第 i 口矿井上建立发电站的费用。
接下来为一个 n×n的矩阵 P,其中 pi,j 表示在第 i 口矿井和第 j 口矿井之间建立电网的费用。
数据保证 pi,j=pj,i且 pi,i=0
输出格式
输出一个整数,表示让所有矿井获得充足电能的最小花费。
数据范围
1≤n≤300
0≤vi,pi,j≤105
输入样例:
4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0
输出样例:
9
#include<bits/stdc++.h>
using namespace std;
const int N=310;
int n,w[N][N],d[N];
bool st[N];
int prim()
{
memset(d,0x3f,sizeof d);
d[0]=0;
int ans=0;
for(int i=0;i<=n;i++){
int t=-1;
for(int j=0;j<=n;j++){
if(!st[j]&&(t==-1||d[t]>d[j])){
t=j;
}
}
st[t]=true;
ans+=d[t];
for(int j=0;j<=n;j++)d[j]=min(d[j],w[t][j]);
}
return ans;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++){
cin>>w[0][i];
w[i][0]=w[0][i];
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>w[i][j];
}
}
cout<<prim();
return 0;
}
7 1148 秘密的牛奶运输
农夫约翰要把他的牛奶运输到各个销售点。
运输过程中,可以先把牛奶运输到一些销售点,再由这些销售点分别运输到其他销售点。
运输的总距离越小,运输的成本也就越低。
低成本的运输是农夫约翰所希望的。
不过,他并不想让他的竞争对手知道他具体的运输方案,所以他希望采用费用第二小的运输方案而不是最小的。
现在请你帮忙找到该运输方案。
注意::
- 如果两个方案至少有一条边不同,则我们认为是不同方案;
- 费用第二小的方案在数值上一定要严格大于费用最小的方案;
- 答案保证一定有解;
输入格式
第一行是两个整数 N,M表示销售点数和交通线路数;
接下来 M 行每行 3 个整数 x,y,z,表示销售点 x 和销售点 y 之间存在线路,长度为 z。
输出格式
输出费用第二小的运输方案的运输总距离。
数据范围
1≤N≤500
1≤M≤104
1≤z≤109
数据中可能包含重边。
输入样例:
4 4
1 2 100
2 4 200
2 3 250
3 4 100
输出样例:
450
#include<bits/stdc++.h>
using namespace std;
const int N=510,M=10010;
int h[N],e[N*2],ne[N*2],w[N*2],idx;
int dist1[N][N],dist2[N][N];
int p[N];
int n,m;
typedef long long LL;
struct T{
int a,b,w;
bool f;
}s[M];
void add(int a,int b,int c)
{
e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
int find(int x)
{
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
bool cmp(T a,T b)
{
return a.w<b.w;
}
void dfs(int u,int fa,int maxx1,int maxx2,int d1[],int d2[])
{
d1[u]=maxx1,d2[u]=maxx2;
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(j!=fa){
int t1=maxx1,t2=maxx2;
if(w[i]>t1)t2=t1,t1=w[i];
else if(w[i]<t1&&w[i]>t2)t2=w[i];
dfs(j,u,t1,t2,d1,d2);
}
}
}
int main()
{
cin>>n>>m;
memset(h,-1,sizeof h);
for(int i=0;i<m;i++){
int a,b,w;
cin>>a>>b>>w;
s[i]={a,b,w};
}
sort(s,s+m,cmp);
LL sum=0;
for(int i=1;i<=n;i++)p[i]=i;
for(int i=0;i<m;i++){
int a=s[i].a,b=s[i].b,w=s[i].w;
int pa=find(a),pb=find(b);
if(pa!=pb)
{
p[pa]=b;
sum+=w;
add(a,b,w),add(b,a,w);
s[i].f=true;
}
}
for(int i=1;i<=n;i++)dfs(i,-1,-1e9,-1e9,dist1[i],dist2[i]);
LL ans=1e18;
for(int i=0;i<m;i++){
if(!s[i].f){
int a=s[i].a,b=s[i].b,w=s[i].w;
LL t;
if(w>dist1[a][b])t=sum+w-dist1[a][b];
else if(w>dist2[a][b])t=sum+w-dist2[a][b];
ans=min(ans,t);
}
}
cout<<ans;
return 0;
}