HDU 1879 继续畅通工程


题目大意: 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;
}


 

 
 

 


 

你可能感兴趣的:(最小生成树)