pyf的愿望
题目大意:
现在已知一共有n(1<=n<=300)个宿舍,宿舍被数字1到n标记。一个宿舍有两种办法能用上Wi-Fi。一种是从其他宿舍链接网线,一种是自己去安装网络设备。自己安装网络设备需要花费w[i],连接两个宿舍需要花费P[i][j] (连接i宿舍和j宿舍要花费P元)。
输入格式:
第一行:一个n
第二行到第n+1行:包含一个数w[i];
第n+2行到2n+1行:第n+1+i行,每行n个数,第j个数表示P[i][j]
输出格式:
第一行:一个最小代价
样例:
4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0
输出:
9
分析:
首先可以看出,每个节点都相互连接,各自拥有一个权值,所以可以很容易看出是个最小生成树的题。不同于大多数的最小生成树的题,这个可以每个点自己直接生成,那么可以创造一个虚拟点,下标为0(因为点的下表是1–n),然后将这个下标为0的点放到这个生成树中,正常套用kruskal算法即可,直接上代码。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair <int,int> PII;
const long long mod=1e5+3;
const int INF=1e9;
const int N=1e5+10;
int n;
int cnt;
int p[310];
int w[N];
struct node
{
int a,b,w;
}ed[N];
bool cmp(node x,node y)
{
return x.w<y.w;
}
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
ll kruskal() //并查集维护
{
sort(ed,ed+cnt,cmp);
ll res=0;
for(int i=0;i<cnt;i++)
{
int a=find(ed[i].a);
int b=find(ed[i].b);
if(a!=b)
{
p[a]=b;
res=res+ed[i].w;
}
}
return res;
}
int main()
{
ios::sync_with_stdio(false),cin.tie(0);
cin>>n;
for(int i=0;i<=n;i++)
{
p[i]=i;
}
for(int i=1;i<=n;i++)
{
cin>>w[i];
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
int k;
cin>>k;
if(i==j) //自己单独买WIFI,和虚拟点连接
{
ed[cnt].a=0;
ed[cnt].b=i;
ed[cnt++].w=w[i];
}
else
{
ed[cnt].a=j;
ed[cnt].b=i;
ed[cnt++].w=k;
}
}
}
cout<<kruskal()<<endl;
return 0;
}