poj1789

来源:互联网 发布:mac 控制台 删除记录 编辑:程序博客网 时间:2024/06/06 01:12

第一道近似自己A的题~

这道题题目英文太长,看不懂。。。直接搜博客看懂了题目,大概就是输入n个7位字符串,然后判断这些字符串根据哪一串衍生出的,就是每个字符串之间的字母会不同,不同的字母个数就是代价,对于每一个字符串都找到与其最相近的字符(代价最小的),就是最小生成树啦,注意为什么是一个树而不是森林,因为题目说了每一个字符串都是由另外的字符串衍生出来的,贴上谷歌翻译的一段题目:

今天,ACM足以支付历史学家研究其历史。历史学家试图找出的一件事就是所谓的衍生计划 - 即卡车类型的衍生方式。他们将卡车类型的距离定义为卡车类型代码中具有不同字母的位置数。他们还认为,每种卡车类型都是从另外一种卡车类型中获得的(除了不是从任何其他类型获得的第一种卡车类型)
以上得知这必然是一颗最小生成树,算法导论刚学的知识,课上介绍了两种算法,本文使用了prim,贴下prim的伪代码:
这里写图片描述
有了上述的伪代码,剩下的就没什么啦,当然输入输出的格式使用的是一个char二维数组,虽然题目介绍每行是7个但是申明的时候需要8个,因为最后一个保存结束符‘\0’啊!伪代码使用了最小堆的方法每次挑选最小的key,key[i]值代表了节点i与已得到的mst子集中所有元素最短的距离。从理论上来说,选出的那个边就是轻量边,对已得到的MST子集是安全的!
好了直接上代码:

#include <iostream>#include<queue>#include<string.h>using namespace std;char str[2001][8];int dis[2001][2001];int key[2001];int vis[2001];int n;int dist(char a[],char b[]){int result=0;for(int i=0;i<7;i++)    if(a[i]!=b[i]) result++;return result;}int prim(){    int result=0;    int flag=0;memset(vis,0,sizeof(vis));for(int i=0;i<n;i++){   key[i]=100;}key[0]=0;while(1){        flag=0;    for(int i=0;i<n;i++)        if(vis[i]==0) flag=1;//仍有元素没有遍历到,树没有形成   if(flag==0) break;    int kv=1000,pos;    for(int i=0;i<n;i++){      if(key[i]<kv&&!vis[i])            kv=key[pos=i];    }//找到最小的key,加入MST子集    vis[pos]=1;   for(int i=0;i<n;i++)        if(!vis[i]&&dis[pos][i]<key[i])             key[i]=dis[pos][i];//及时更改其他的key}for(int i=0;i<n;i++)    result+=key[i];//key代表了边上的权重,加起来就是总代价啦!return result;}int main(){   while(cin>>n&&n){    for(int i=0;i<n;i++)      cin>>str[i];    memset(dis,-1,sizeof(dis));    for(int i=0;i<n-1;i++)    for(int j=i+1;j<n;j++)    {    dis[i][j]=dis[j][i]=dist(str[i],str[j]);     }     cout<<"The highest possible quality is 1/"<<prim()<<"."<<endl;   }   return 0;}

没有用到pi数组,因为不需要知道路径到底是怎么走的啊,只要求总代价就行了,pi数组中表示每一个节点的直接相邻的前驱节点,根据这个pi就可以得到生成树具体长什么样!!!!

0 0
原创粉丝点击