题目大意: n个村庄,两两有路,有一些已经建成,有一些未建成,问求使得任意两个村庄都可以连通的最小费用
思路:已经建成的路令其费用为0,求最小生成树即可.
解法一:这里用最简单的prim+邻接矩阵:果断很慢O(n^2)450ms
AC Program:
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <string.h>
typedef long long ll;
#define clr(a) memset((a),0,sizeof (a))
#define rep(i,a,b) for(int i=(a);i<(int)(b);i++)
#define per(i,a,b) for(int i=((a)-1);i>=(int)(b);i--)
#define inf (0x7fffffff)
#define eps 1e-6
#define MAXN
#define MODN (1000000007)
using namespace std;
int n;
int mm[110][110];
int vis[110];
int dis[110];
void prim(){
for(int i=1;i<=n;i++){
vis[i]=0;
dis[i]=mm[1][i];
}
dis[1]=0;
vis[1]=1;
int k,min;
for(int i=1;i<=n;i++){
min=inf;
for(int j=1;j<=n;j++){
if(!vis[j]&&min>dis[j]){
min=dis[j];
k=j;
}
}
vis[k]=1;
for(int j=1;j<=n;j++){
if(!vis[j]&&dis[j]>mm[k][j]){
dis[j]=mm[k][j];
}
}
}
int sum=0;
for(int i=1;i<=n;i++){
sum+=dis[i];
}
printf("%d\n",sum);
}
int main(){
int u,v,w,sta;
while(~scanf("%d",&n)&&n){
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
mm[i][j]=inf;
int edge=n*(n-1)/2;
for(int i=1;i<=edge;i++){
scanf("%d%d%d%d",&u,&v,&w,&sta);
if(sta==1){
mm[u][v]=0;//一开始忘了建立双向边,晕
mm[v][u]=0;
}
else{
mm[u][v]=w;
mm[v][u]=w;
}
}
prim();
};
//system("pause");
return 0;
}
解法二:想玩一下邻接表,就了.prim+邻接表,想象中更慢 O(n*m) 680ms
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <string.h>
typedef long long ll;
#define clr(a) memset((a),0,sizeof (a))
#define rep(i,a,b) for(int i=(a);i<(int)(b);i++)
#define per(i,a,b) for(int i=((a)-1);i>=(int)(b);i--)
#define inf (0x7fffffff)
#define eps 1e-6
#define MAXN
#define MODN (1000000007)
using namespace std;
int n;
//int mm[110][110];
int head[110];
int vis[110];
int dis[110];
struct edge{
int to,w,next;
}e[5500*100+5];
void prim(){
for(int i=1;i<=n;i++){ //初始化标记数组和距离数组
vis[i]=0;
dis[i]=inf;
}
for(int i=head[1];i!=-1;i=e[i].next){//寻找1可以到的点初始化
int ti=e[i].to;//一开始没有这句话,囧..这是因为to是要用来初始化,不是边的编号用来初始化
dis[ti]=e[i].w;
//cout<<"i "<<i<<endl;
}
dis[1]=0;
vis[1]=1;
/*/-----
for(int i=1;i<=n;i++){
cout<<"dis[i] "<<dis[i]<<" "<<endl;
}
/*/
int k,min;
for(int i=1;i<=n;i++){
min=inf;
for(int j=1;j<=n;j++){
if(!vis[j]&&min>dis[j]){ //必须扫描一遍找出最短的
min=dis[j];
k=j;
}
}
vis[k]=1;
for(int j=head[k];j!=-1;j=e[j].next){//找出当前点可以到的边进行更新
int tj=e[j].to;
if(!vis[tj]&&dis[tj]>e[j].w)
dis[tj]=e[j].w;
}
/*
for(int j=1;j<=n;j++){
if(!vis[j]&&dis[j]>mm[k][j]){
dis[j]=mm[k][j];
}
}
*/
}
int sum=0;
for(int i=1;i<=n;i++){
sum+=dis[i];
}
printf("%d\n",sum);
}
int main(){
int u,v,wei,sta;
while(~scanf("%d",&n)&&n){
int edge=n*(n-1)/2;
int cnt=0;
memset(head,-1,sizeof(head));
memset(e,0,sizeof(e));
for(int i=1;i<=edge;i++){
scanf("%d%d%d%d",&u,&v,&wei,&sta);
if(sta==1){ //初始化,建立邻接表
e[cnt].to=v;
e[cnt].w=0;
e[cnt].next=head[u];
head[u]=cnt++;
e[cnt].to=u;
e[cnt].w=0;
e[cnt].next=head[v];
head[v]=cnt++;
}
else{
e[cnt].to=v;
e[cnt].w=wei;
e[cnt].next=head[u];
head[u]=cnt++;
e[cnt].to=u;
e[cnt].w=wei;
e[cnt].next=head[v];
head[v]=cnt++;
}
}
prim();
};
//system("pause");
return 0;
}