专题地址:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=66965#overview
A 裸的最小生成树,Kruskal算法。
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
typedef long long ll;
const int maxn=3000;
const int maxm=100000;
int parent[maxn];
int tot;
struct Edge
{
int u,v,w;
}edge[maxm];
void addedge(int u,int v,int w)
{
edge[tot].u=u;
edge[tot].v=v;
edge[tot++].w=w;
}
int find(int x)
{/*
if(parent[x]==x)
return x;
parent[x]=find(parent[x]);
return parent[x];*/
return parent[x]==x?x:find(parent[x]);
}
bool cmp(Edge a,Edge b)
{
return a.w<b.w;
}
void init(int n)
{
for(int i=0;i<=n;i++)
parent[i]=i;
tot=0;
}
int kruscal(int n)
{
sort(edge,edge+tot,cmp);
int cnt=0;
int ans=0;
for(int i=0;i<tot;i++)
{
int u=edge[i].u;
int v=edge[i].v;
int w=edge[i].w;
int t1=find(u);
int t2=find(v);
if(t1!=t2)
{
parent[t1]=t2;
ans+=w;
cnt++;
}
if(cnt==n-1)
break;
}
if(cnt<n-1)
return -1;
else
return ans;
}
int n;
int main()
{
while(rd(n)!=EOF&&n)
{
char ch;int m;
init(n);
for(int i=1;i<=n-1;i++)
{
cin>>ch;
int u=ch-'A'+1;
rd(m);
char to;int w;
while(m--)
{
cin>>to;
int v=to-'A'+1;
rd(w);
addedge(u,v,w);
}
}
printf("%d\n",kruscal(n));
}
return 0;
}
B 裸的最小生成树,用Prim算法。注意两点之间可能有多条边。
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
typedef long long ll;
const int maxn=60;
const int inf=0x3f3f3f3f;
int cost[maxn][maxn];
bool vis[maxn];
int lowc[maxn];
int n,m;
int Prim(int cost[][maxn],int n)
{
int ans=0;
memset(vis,0,sizeof(vis));
vis[0]=true;
for(int i=1;i<n;i++)
lowc[i]=cost[0][i];
for(int i=1;i<n;i++)
{
int minc=inf;
int p=-1;
for(int j=0;j<n;j++)
if(!vis[j]&&minc>lowc[j])
{
minc=lowc[j];
p=j;
}
if(minc==inf) return -1;//不连通
ans+=minc;
vis[p]=true;
for(int j=0;j<n;j++)
if(!vis[j]&&lowc[j]>cost[p][j])
lowc[j]=cost[p][j];
}
return ans;
}
int main()
{
while(rd(n)!=EOF&&n)
{
rd(m);
int u,v,w;
memset(cost,inf,sizeof(cost));
while(m--)
{
rd3(u,v,w);
u--;v--;
if(w<cost[u][v])
{
cost[u][v]=w;
cost[v][u]=w;
}
}
printf("%d\n",Prim(cost,n));
}
return 0;
}
C 空间中有n个小球,给出每个小球的三维坐标和半径,小球可以相互接触也可以重叠,n个小球连接起来,求最小的通道长度。计算任意两个小球之间的距离(注意接触或者重叠距离为0),然后用最小生成树就可以了。
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
typedef long long ll;
const int maxn=110;
double cost[maxn][maxn];
bool vis[maxn];
const double inf=1000000;
const double eps=1e-8;
double lowc[maxn];
struct Point
{
double x,y,z,r;
void input()
{
scanf("%lf%lf%lf%lf",&x,&y,&z,&r);
}
double distance(Point p)
{
double dis=sqrt((x-p.x)*(x-p.x)+(y-p.y)*(y-p.y)+(z-p.z)*(z-p.z));
if(dis-r-p.r>eps)
return dis-r-p.r;
else
return 0;
}
}point[maxn];
int n;
double Prim(double cost[][maxn],int n)
{
memset(vis,0,sizeof(vis));
double ans=0;
vis[0]=1;
for(int i=1;i<n;i++)
lowc[i]=cost[0][i];
for(int i=1;i<n;i++)
{
double minc=inf;
int p=-1;
for(int j=0;j<n;j++)
{
if(minc>lowc[j]&&!vis[j])
{
p=j;
minc=lowc[j];
}
}
ans+=minc;
vis[p]=1;
for(int j=0;j<n;j++)
{
if(!vis[j]&&lowc[j]>cost[p][j])
lowc[j]=cost[p][j];
}
}
return ans;
}
int main()
{
while(rd(n)!=EOF&&n)
{
for(int i=0;i<n;i++)
{
point[i].input();
}
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cost[i][j]=inf;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
double dis=point[i].distance(point[j]);
if(dis<cost[i][j])
cost[i][j]=cost[j][i]=dis;
}
printf("%.3f\n",Prim(cost,n));
}
return 0;
}
D 有N个村庄,给定任意两个村庄之间的距离,并且给出一些已经存在的路(边),问最少共再需要多长的路使得N个村庄联通。最小生成树,本题就是有个条件已经存在一些边了,用Prim算法求的是总长度,且每次都是找的最小的边,那么只要把已经存在的边权值设为0就好了,因为每次都是找最小的边,那么这些边肯定会被选择的,而且用prim算法求完后也正好是题目所求的长度。
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
typedef long long ll;
const int maxn=104;
const int inf=0x3f3f3f3f;
int cost[maxn][maxn];
int lowc[maxn];
bool vis[maxn];
int n,m;
int Prim(int cost[][maxn],int n)
{
int ans=0;
memset(vis,0,sizeof(vis));
vis[0]=true;
for(int i=1;i<n;i++)
lowc[i]=cost[0][i];
for(int i=1;i<n;i++)//寻找这么多次
{
int p=-1,minc=inf;
for(int j=0;j<n;j++)
{
if(minc>lowc[j]&&!vis[j])
{
minc=lowc[j];
p=j;
}
}
vis[p]=1;
ans+=minc;
for(int j=0;j<n;j++)
{
if(!vis[j]&&lowc[j]>cost[p][j])
lowc[j]=cost[p][j];
}
}
return ans;
}
int main()
{
rd(n);
memset(cost,inf,sizeof(cost));
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
rd(cost[i][j]);
}
rd(m);
int u,v;
while(m--)
{
rd2(u,v);
u--;v--;
cost[u][v]=cost[v][u]=0;
}
printf("%d\n",Prim(cost,n));
return 0;
}
E 有n个节点,每个节点都有一个权值,然后给出任意两个节点之间的距离,要在两个节点之间连边,使得这n个节点联通,连边的代价除了两点之间边的距离之外还有两点各自的权值之和。在cost矩阵中,加入两个点的权值,然后求最小生成树。
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
typedef long long ll;
const int maxn=1004;
const int inf=0x3f3f3f3f;
int cost[maxn][maxn];
int lowc[maxn];
bool vis[maxn];
int val[maxn];
int n,m;
int Prim(int cost[][maxn],int n)
{
int ans=0;
memset(vis,0,sizeof(vis));
vis[0]=true;
for(int i=1;i<n;i++)
lowc[i]=cost[0][i];
for(int i=1;i<n;i++)//寻找这么多次
{
int p=-1,minc=inf;
for(int j=0;j<n;j++)
{
if(minc>lowc[j]&&!vis[j])
{
minc=lowc[j];
p=j;
}
}
vis[p]=1;
ans+=minc;
for(int j=0;j<n;j++)
{
if(!vis[j]&&lowc[j]>cost[p][j])
lowc[j]=cost[p][j];
}
}
return ans;
}
int main()
{
int t;rd(t);
while(t--)
{
rd(n);
memset(cost,inf,sizeof(cost));
for(int i=0;i<n;i++)
rd(val[i]);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
rd(cost[i][j]);
cost[i][j]+=val[i]+val[j];
}
printf("%d\n",Prim(cost,n));
}
return 0;
}
F 给出N个长度为7的字符串,两个字符串之间定义距离为 两个字符串每个位置字母不同的个数,一个字符串可以生成另一个字符串,代价为两个字符串的距离,问这n个字符串最小的代价。 把任意两个字符串之间的距离求出来,然后进行最小生成树。
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
typedef long long ll;
const int maxn=2002;
const int inf=0x3f3f3f3f;
int cost[maxn][maxn];
int lowc[maxn];
bool vis[maxn];
string str[maxn];
int n;
int cal(int i,int j)
{
int cnt=0;
for(int k=0;k<7;k++)
if(str[i][k]!=str[j][k])
cnt++;
return cnt;
}
int Prim(int cost[][maxn],int n)
{
int ans=0;
memset(vis,0,sizeof(vis));
vis[0]=1;
for(int i=1;i<n;i++)
lowc[i]=cost[0][i];
for(int i=1;i<n;i++)
{
int minc=inf,p=-1;
for(int j=0;j<n;j++)
{
if(!vis[j]&&minc>lowc[j])
{
minc=lowc[j];
p=j;
}
}
vis[p]=1;
ans+=minc;
for(int j=0;j<n;j++)
{
if(!vis[j]&&lowc[j]>cost[p][j])
lowc[j]=cost[p][j];
}
}
return ans;
}
int main()
{
while(rd(n)!=EOF&&n)
{
for(int i=0;i<n;i++)
cin>>str[i];
memset(cost,inf,sizeof(cost));
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
{
int w=cal(i,j);
if(w<cost[i][j])
cost[i][j]=cost[j][i]=w;
}
printf("The highest possible quality is 1/%d.\n",Prim(cost,n));
}
return 0;
}
G 题意为有N个部落以及它们的坐标,然后有P个卫星,如果两个部落都有一个卫星的话,那么这两个部落无论距离多远都能通信,否则,两个部落只能依靠无线电通信,条件是只有两个部落的距离不超过D,两个部落才能通信,求最小的D,使得这N个部落都能通信。也就是在这N个部落里面找N-1条边,使得他们相互连通,P个卫星肯定是放在距离最大的村庄上,这样省去了P-1条边,所以我们只要再找N-1-(P-1)条边就好了,要求最小的D,也就是求这N-1-(P-1)条边里面的最大边的值。
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
typedef long long ll;
const int maxn=510;
const double inf=100000000.0;
double cost[maxn][maxn];
double lowc[maxn];
bool vis[maxn];
double edge[maxn];
struct Point
{
double x,y;
void input()
{
scanf("%lf%lf",&x,&y);
}
double distance(Point p)
{
return hypot(x-p.x,y-p.y);
}
}point[maxn];
int n,P;
double Prim(double cost[][maxn],int n)
{
memset(vis,0,sizeof(vis));
vis[0]=1;
for(int i=1;i<n;i++)
lowc[i]=cost[0][i];
int cnt=0;
for(int i=1;i<n;i++)
{
double minc=inf;
int p=-1;
for(int j=0;j<n;j++)
{
if(!vis[j]&&minc>lowc[j])
{
minc=lowc[j];
p=j;
}
}
edge[cnt++]=minc;
vis[p]=1;
for(int j=0;j<n;j++)
{
if(!vis[j]&&lowc[j]>cost[p][j])
lowc[j]=cost[p][j];
}
}
sort(edge,edge+cnt);//别忘了排序
return edge[cnt-P];
}
int main()
{
int t;rd(t);
while(t--)
{
rd2(P,n);
for(int i=0;i<n;i++)
point[i].input();
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cost[i][j]=inf;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
double dis=point[i].distance(point[j]);
if(dis<cost[i][j])
cost[i][j]=cost[j][i]=dis;
}
printf("%.2f\n",Prim(cost,n));
}
return 0;
}
H 给定n个节点以及这n个节点的坐标,另外给出了m条已经现有的边,求要使这n个点连通,还需要建多少边,输出需要建边的两个端点编号。和上面有个题差不多,也是把给出的边的权值设置为0,然后pre[i]表示i节点所在边的另一个节点,最小生成树选择一条边以后,输出pre[p], p 就可以了。为了避免已经存在的边输出,判断一下是否cost[i][j] >0。因为刚才已存在的边已经赋值为0了。
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
typedef long long ll;
const int maxn=1000;
const int inf=0x3f3f3f3f;
bool vis[maxn];
int cost[maxn][maxn];
int lowc[maxn];
int pre[maxn];
int n,m;
struct Point
{
int x,y;
int distance(Point p)
{
return (x-p.x)*(x-p.x)+(y-p.y)*(y-p.y);
}
}point[maxn];
void Prim()
{
memset(vis,0,sizeof(vis));
for(int i=1;i<n;i++)
{
lowc[i]=cost[0][i];
pre[i]=0;
}
vis[0]=1;int p=-1;
for(int i=1;i<n;i++)
{
int minc=inf;
for(int j=0;j<n;j++)
{
if(!vis[j]&&minc>lowc[j])
{
minc=lowc[j];
p=j;
}
}
vis[p]=1;
if(cost[pre[p]][p])
printf("%d %d\n",pre[p]+1,p+1);
for(int j=0;j<n;j++)
{
if(lowc[j]>cost[p][j]&&!vis[j])
{
lowc[j]=cost[p][j];
pre[j]=p;
}
}
}
}
int main()
{
rd(n);
memset(cost,inf,sizeof(cost));
for(int i=0;i<n;i++)
rd2(point[i].x,point[i].y);
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
{
int dis=point[i].distance(point[j]);
if(cost[i][j]>dis)
cost[i][j]=cost[j][i]=dis;
}
rd(m);
int u,v;
while(m--)
{
rd2(u,v);
u--;v--;
cost[u][v]=cost[v][u]=0;
}
Prim();
return 0;
}
I 裸的最小生成树
const int maxn=5010;
int parent[110];
int n;
struct Node
{
int from,to,edge;
}node[maxn];
void init(int n)
{
for(int i=1;i<=n;i++)
parent[i]=i;
}
int find(int x)
{
return parent[x]==x?x:find(parent[x]);
}
bool cmp(Node a,Node b)
{
if(a.edge<b.edge)
return true;
return false;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
int m=1;
int len;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
scanf("%d",&len);
if(i<j)
{
int temp=m;
node[temp].from=i;
node[temp].to=j;
node[temp].edge=len;
m++;
}
}
init(n);
m=n*(n-1)/2;
len=0;
sort(node+1,node+1+m,cmp);
for(int i=1;i<=m;i++)
{
int x=find(node[i].from);
int y=find(node[i].to);
if(x==y)
continue;
else
{
len+=node[i].edge;
parent[x]=y;
}
}
printf("%d\n",len);
}
return 0;
}
J 在一个迷宫里面#代表不可走,空白可走,存在字母一个‘S' 和多个’A‘ ,要从S出发找到所有的A,可以从S出发分成多路去找A, 问最少的步数和。也就是求最小生成树,节点为S和A,需要知道任意两个节点的最短距离,因为对每个点都用bfs,找出任意两个点之间的最短距离,然后使用最小生成树就可以了。 注意:输入格式,输入迷宫的大小n*m的时候很坑,要使用字符串格式...
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
typedef long long ll;
const int maxn=110;
const int inf=0x3f3f3f3f;
int cost[maxn][maxn];
int lowc[maxn];
bool vis[maxn][maxn];
int tot;
char mp[60][60];
int n,m;
int dx[4]={-1,1,0,0};
int dy[4]={0,0,1,-1};
struct Point
{
int i,j;
}point[maxn];
void BFS(int from,int x,int y)
{
memset(vis,0,sizeof(vis));
int step[maxn][maxn];
step[x][y]=0;
vis[x][y]=1;
queue<Point>q;
Point a;
a.i=x;a.j=y;
q.push(a);
while(!q.empty())
{
Point first=q.front();
q.pop();
for(int i=0;i<4;i++)
{
int newx=first.i+dx[i];
int newy=first.j+dy[i];
if(mp[newx][newy]!='#'&&!vis[newx][newy]&&newx>=0&&newx<n&&newy>=0&&newy<m)
{
a.i=newx;a.j=newy;
vis[newx][newy]=1;
q.push(a);
step[newx][newy]=step[first.i][first.j]+1;
}
}
}
for(int i=0;i<tot;i++)
{
cost[from][i]=step[point[i].i][point[i].j];
}
}
int Prime(int cost[][maxn],int n)
{
bool vis[maxn];
int ans=0;
memset(vis,0,sizeof(vis));
vis[0]=1;
for(int i=1;i<tot;i++)
lowc[i]=cost[0][i];
for(int i=1;i<n;i++)
{
int minc=inf,p=-1;
for(int j=0;j<n;j++)
{
if(!vis[j]&&minc>lowc[j])
{
p=j;
minc=lowc[j];
}
}
ans+=minc;
vis[p]=1;
for(int j=0;j<n;j++)
{
if(!vis[j]&&lowc[j]>cost[p][j])
lowc[j]=cost[p][j];
}
}
return ans;
}
int main()
{
int t;rd(t);
getchar();
while(t--)
{
gets(mp[0]);
sscanf(mp[0],"%d%d",&m,&n);//这里的格式
tot=1;
for(int i=0;i<n;i++)
{
gets(mp[i]);
int len=strlen(mp[i]);
for(int k=0;k<len;k++)
{
if(mp[i][k]=='A')
point[tot].i=i,point[tot++].j=k;
else if(mp[i][k]=='S')
point[0].i=i,point[0].j=k;
}
}
//construct cost[][]
memset(cost,inf,sizeof(cost));
for(int i=0;i<tot;i++)
BFS(i,point[i].i,point[i].j);
/*
for(int i=0;i<tot;i++)
{
for(int j=0;j<tot;j++)
cout<<cost[i][j]<<" ";
cout<<endl;
}
*/
//进行prim
printf("%d\n",Prime(cost,tot));
}
return 0;
}
K 次小生成树,如果最小生成树唯一的话,输出最小权值,否则输出not unique。
http://blog.chinaunix.net/uid-25324849-id-2182922.html
次小生成树
求最小生成树时,用maxval[i][j],表示最小生成树中i到j路径中的最大边权
求完后,直接枚举所有不在最小生成树中的边(比如该边的两端是i,j,
然后替换掉路径i,j中最大边权的边,更新答案
点的编号从0开始。
为什么可以替换、
求完最小生成树后,从i到j有路径,那么路径上的点两两可以相互到达,如果去掉最大边
,那么该路径就切成了两部分,而加入不在最小生成树的一条边(比如该边地两端是i,j)
,那么又把这两部分重新串起来了,重新变得两两可以相互到达。
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
typedef long long ll;
const int maxn=110;
const int inf=0x3f3f3f3f;
bool vis[maxn];
int lowc[maxn];
int pre[maxn];
int cost[maxn][maxn];
int maxval[maxn][maxn];
bool used[maxn][maxn];
int Prim(int cost[][maxn],int n)
{
int ans=0;
memset(vis,0,sizeof(vis));
memset(maxval,0,sizeof(maxval));
memset(used,0,sizeof(used));
vis[0]=true;
pre[0]=-1;
for(int i=1;i<n;i++)
{
lowc[i]=cost[0][i];
pre[i]=0;
}
lowc[0]=0;
for(int i=1;i<n;i++)
{
int minc=inf,p=-1;
for(int j=0;j<n;j++)
{
if(!vis[j]&&minc>lowc[j])
{
minc=lowc[j];
p=j;
}
}
if(minc==inf)
return -1;
ans+=minc;
vis[p]=true;
used[p][pre[p]]=used[pre[p]][p]=true;
for(int j=0;j<n;j++)
{
if(vis[j])
maxval[j][p]=maxval[p][j]=max(maxval[j][pre[p]],lowc[p]);
//为什么这么写,vis[j]代表那么节点已经访问过了,该条边是不能加的,有没有边都没关系,否则成了环,
//那么在路径j->p中,j是路径的起点,p就是路径的终点,而maxval[j][pre[p]],就是起点j到p的上一个节点
//组成的路径的最大边权值,lowc[p],则是带有p的那一边的权值,二者最大值,就是路径j->p的最大权值
//比如 1->2->3->4-------->1,虚线代表有边或者没有边都行,那么此时p=4,j=1, pre[p]=3,
//maxval[j][pre[p]]=maxval[1][3],也就是路径1到3上的最大边的权值,lowc[4]则是3到4上权值,二者的最大值
//则是路径1->4的最大边的权值。
if(!vis[j]&&lowc[j]>cost[p][j])
{
lowc[j]=cost[p][j];
pre[j]=p;
}
}
}
return ans;
}
int ans;//保存最小生成树的值
int smst(int cost[][maxn],int n)//次小生成树
{
int minc=inf;
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
{
if(cost[i][j]!=inf&&!used[i][j])//i,j之间有边,且该边没有在最小生成树中
{
minc=min(minc,ans+cost[i][j]-maxval[i][j]);//用该边替换最小生成树中i,j路径中的最大边
}
}
if(minc==inf)
return -1;
return minc;
}
int n,m;
int main()
{
int t;rd(t);
while(t--)
{
rd2(n,m);
memset(cost,inf,sizeof(cost));
int u,v,w;
while(m--)
{
rd3(u,v,w);
u--;
v--;
if(w<cost[u][v])
cost[u][v]=cost[v][u]=w;
}
ans=Prim(cost,n);
if(ans==smst(cost,n))
printf("Not Unique!\n");
else
printf("%d\n",ans);
}
return 0;
}
L 裸最小生成树
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
typedef long long ll;
const int maxn=110;
const int maxm=5000;
struct Edge
{
int u,v,w;
}edge[maxm];
int tot;//边的个数
int parent[maxn];
void addege(int u,int v,int w)
{
edge[tot].u=u;
edge[tot].v=v;
edge[tot++].w=w;
}
void init(int n)
{
tot=0;
for(int i=0;i<=n;i++)
parent[i]=i;
}
int find(int x)
{
if(parent[x]==x)
return x;
parent[x]=find(parent[x]);
return parent[x];
}
bool cmp(Edge a,Edge b)
{
return a.w<b.w;
}
int n;
int kruskal(int n)
{
sort(edge,edge+tot,cmp);
int cnt=0;//计算加入的边数
int ans=0;
for(int i=0;i<tot;i++)
{
int u=edge[i].u;
int v=edge[i].v;
int w=edge[i].w;
int t1=find(u);
int t2=find(v);
if(t1!=t2)
{
ans+=w;
parent[t1]=t2;
cnt++;
}
if(cnt==n-1)
break;
}
if(cnt<n-1)
return -1;//不连通
else
return ans;
}
int main()
{
while(rd(n)!=EOF&&n)
{
init(n);
int u,v,w;
for(int i=1;i<=n*(n-1)/2;i++)
{
rd3(u,v,w);
addege(u,v,w);
}
printf("%d\n",kruskal(n));
}
return 0;
}
N 同裸,浮点数。
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
#include <cmath>
#include <iomanip>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cctype>
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
typedef long long ll;
const int maxn=110;
struct Point
{
double x,y;
double distance(Point p)
{
return hypot(x-p.x,y-p.y);
}
}point[maxn];
const double inf=100000.0;
bool vis[maxn];
double lowc[maxn];
double cost[maxn][maxn];
double Prim(double cost[][maxn],int n)
{
double ans=0;
memset(vis,0,sizeof(vis));
vis[0]=true;
for(int i=1;i<n;i++)
lowc[i]=cost[0][i];
for(int i=1;i<n;i++)
{
double minc=inf;
int p=-1;
for(int j=0;j<n;j++)
{
if(!vis[j]&&minc>lowc[j])
{
minc=lowc[j];
p=j;
}
}
if(minc==inf)
return -1.0;
ans+=minc;
vis[p]=true;
for(int j=0;j<n;j++)
if(!vis[j]&&lowc[j]>cost[p][j])
lowc[j]=cost[p][j];
}
return ans;
}
int n;
int main()
{
int t;rd(t);
while(t--)
{
rd(n);
for(int i=0;i<n;i++)
scanf("%lf%lf",&point[i].x,&point[i].y);
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
cost[i][j]=inf;
}
/*
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
cout<<cost[i][j]<<" ";
cout<<endl;
}
*/
for(int i=0;i<n;i++)
{
for(int j=i+1;j<n;j++)
{
double dis=point[i].distance(point[j]);
if(dis<cost[i][j]&&dis>=10&&dis<=1000)
{
cost[i][j]=dis;
cost[j][i]=dis;
}
}
}
double ans=Prim(cost,n);
if(ans==-1.0)
printf("oh!\n");
else
printf("%.1f\n",ans*100);
}
return 0;
}