//poj-1789 :
题目大意:题意大概是这样的:用一个7位的string代表一个编号,两个编号之间的distance代表这两个编号之间不同字母的个数。一个编号只能由另一个编号“衍生”出来,代价是这两个编号之间相应的distance,现在要找出一个“衍生”方案,使得总代价最小,也就是distance之和最小。
Sample Input
4
aaaaaaa
baaaaaa
abaaaaa
aabaaaa
0
Sample Output
The highest possible quality is 1/3.
*********************************************************************
AC Code1:Kruskal emory: 22848K Time: 594MS
貌似kruskal真不太适合稠密图,用时594Ms
#include <algorithm>#include <iostream>
#include <cstdio>
#include <cstring>
#define MaxE 2000000
using namespace std;
struct Edge{int from,to,value;}edge[MaxE];
int size;
bool cmp(Edge a,Edge b)
{ if(a.value<b.value) return true; return false; }
char str[2005][8];
int father[2005];
int n; //点数
int value;//记录最终的边权和
int find(int x)
{ if(x!=father[x]) return father[x]=find(father[x]);
return father[x];
}
void Union(int a,int b)
{ int x=father[a]; int y=father[b];
if(x!=y) father[y]=father[x];
return;
}
void kruskal()
{int i; int x,y,k=0; value=0;
sort(edge,edge+size,cmp); //按边权值从小到大排序
for(i=0;i<size;i++)
{ x=find(edge[i].from); y=find(edge[i].to);
if(x==y) continue;
k++;
Union(edge[i].from,edge[i].to);
value+=edge[i].value;
if(k==n-1) break;
}
if(k!=n-1) value=-1; //边权和赋为-1,标记不能生成树
}
void init()//初始化
{ int i,j,k,a;
for(i=0;i<2005;i++) father[i] = i;
size=0;
memset(str,0,sizeof(str));
for(i=1;i<=n;i++)
scanf("%s",str[i]);
for(i=1;i<=n;i++)
{ for(j=i+1;j<=n;j++)
{ a=0;
for(k=0;k<7;k++) { if(str[i][k]-str[j][k]) a++; }
edge[size].from=i;
edge[size].to=j;
edge[size++].value=a;
}
}
}
int main()
{//freopen("in.txt","r",stdin);
while(scanf("%d",&n)!=EOF)
{ if(n==0) break;
init();
kruskal();
printf("The highest possible quality is 1/%d.\n",value);
}
return 0;
}
*********************************************************************
AC Code2:Prim emory: 15620K Time: 313MS
//神奇的是:init()中判断语句中
将if(str[i][k]-str[j][k])改成了if(str[i][k]!=str[j][k]),时间缩短了一半。以后判断两个字符是否相等就不要用 字符想减 了。。。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define Inf 8
using namespace std;
int n;
int map[2005][2005];
int dist[2005];
char str[2005][8];
bool p[2005];
int value;//记录最终值,最小边权和
void prim() //默认从第一点开始建树
{ int i,j; int k=0; int s,num,min;
value=0; memset(p,0,sizeof(p));
for(i=1;i<=n;i++) dist[i]=Inf;
s=1;
while(1)
{ p[s]=1; k++;
if(k==n) break;
min=Inf; num=0;
for(j=2;j<=n;j++)
{ if(p[j]) continue;
if(dist[j]>map[s][j]) dist[j]=map[s][j];
if(dist[j]<min) //将该回合最小边找出来
{ num=j; min=dist[j]; }
}
s=num;
value+=min;
}
}
void init()
{int i,j,k; int a;
//memset(str,0,sizeof(str)); //memset(map,0,sizeof(map));
for(i=1;i<=n;i++) scanf("%s",str[i]);
for(i=1;i<=n-1;i++)
{ for(j=i+1;j<=n;j++)
{ a=0;
for(k=0;k<7;k++) { if(str[i][k]!=str[j][k]) a++; }
map[i][j]=map[j][i]=a;
}
}
}
int main()
{ //freopen("in.txt","r",stdin);
while(scanf("%d",&n)!=EOF)
{ if(n==0) break;
init();
prim();
printf("The highest possible quality is 1/%d.\n",value);
}
return 0;
}