poj 1789  最小生成树

本文探讨如何通过Prim算法解决在给定卡车代码的情况下,求解衍生这些卡车的最小代价问题,避免了超时风险。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:这个题目真他妈的是在考英语 。 割!!!

意思是说,给出n个卡车的代码 , 而卡车a衍生卡车b代价为a和b代码不相同字母的个数 , 问,衍生了这么多的卡车 , 最小的代价是什么。(每辆卡车可以有任何一个卡车衍生而来 , 除本身外!) 所以,明显是在求最下生成树 , 由题意可知 , 建成的图为稠密图 , 所以用prim算法 。但要注意优化 , 不然超时。

割   

代码1、  超时了:

#include
#include
using namespace std;

char car[2010][10] ;
int grap[2010][2010] ;
int n;
int bz[2010] , queue[2010] ;

int main()
{
 //int p;
 while(scanf("%d" , &n) &&n)
 {
  int i , j;
 // cin>>n;
  for(i = 1 ; i <= n; i++)
   cin>>car[i];
  memset(grap , 0 , sizeof(grap));
  for(i = 1 ; i <= n; i++)
  {
   for(j = i+1 ; j <= n ; j++)
   {
    int sum = 0;
    for(int k = 0 ; k < 7 ; k++)
     if(car[i][k] != car[j][k])  sum += 1;
    grap[i][j] = grap[j][i] = sum ;
   }
  
  }
  queue[1] = 1;
  j = 2;
  memset(bz , 0 , sizeof(bz));
  int sum = 0;
  bz[1] = 1;
 
  for(i = 1 ; i < n; i++)
  {
   int max = 99999 , min = 0;
   for(int k = 2 ; k <= n; k++)
   {
   
    int x = queue[k];
    for(int g = 1 ; g <= n ; g++)
    {
     if(!bz[g] && grap[x][g])
      if(max > grap[x][g])  {max = grap[x][g] ; min = g;}
    }
   }
   if(min != 0)
   {
    sum += max;
    queue[j++] = min;
    bz[min] = 1;
   }
  
  }
  printf("The highest possible quality is 1/%d.\n" , sum);
 }
 return 0;
  这是初学者最容易犯的一个错误, 因为书上就这么讲的 。

 

 

 

代码2、

//Memory Time
//15688K 344MS

#include
#include
using namespace std;

const int inf=10;          //无穷大(两点间边权最大为7)
const int large=2001;

int n;  //truck types
char str[large][8];
int dist[large][large]={0};

int weight(int i,int j)     //返回两个字符串中不同字符的个数(返回边权)
{
 int w=0;
 for(int k=0;k<7;k++)
  if(str[i][k]!=str[j][k])
   w++;
 return w;
}

int prim(void)
{
 int s=1;       //源点(最初的源点为1)
 int m=1;       //记录最小生成树的顶点数
 bool u[large]; //记录某顶点是否属于最小生成树
 int prim_w=0;  //最小生成树的总权值
 int min_w;     //每个新源点到其它点的最短路
 int flag_point;
 int low_dis[large];  //各个源点到其它点的最短路

 memset(low_dis,inf,sizeof(low_dis));
 memset(u,false,sizeof(u));
 u[s]=true;

 while(1)
 {
  if(m==n)      //当最小生成树的顶点数等于原图的顶点数时,说明最小生成树查找完毕
   break;

  min_w=inf;
  for(int j=2;j<=n;j++)
  {
   if(!u[j] && low_dis[j]>dist[s][j])
    low_dis[j] = dist[s][j];
   if(!u[j] && min_w>low_dis[j])
   {
    min_w=low_dis[j];
    flag_point=j;      //记录最小权边中不属于最小生成树的点j
   }
  }
  s=flag_point;       //顶点j与旧源点合并
  u[s]=true;          //j点并入最小生成树(相当于从图上删除j点,让新源点接替所有j点具备的特征)
  prim_w+=min_w;      //当前最小生成树的总权值
  m++;               
 }
 return prim_w;
}

int main(void)
{
 int i,j;

 while(cin>>n && n)
 {
  
  
  for(i=1;i<=n;i++)
   cin>>str[i];

  

  for(i=1;i<=n-1;i++)
   for(j=i+1;j<=n;j++)
    dist[i][j]=dist[j][i]=weight(i,j);

  

  cout<<"The highest possible quality is 1/"<<prim()<<'.'<<endl;

 }
 return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值