poj1789 Truck History
题意大概是这样的:用一个7位的string代表一个编号,两个编号之间的distance代表这两个编号之间不同字母的个数。一个编号只能由另一个编号“衍生”出来,代价是这两个编号之间相应的distance,现在要找出一个“衍生”方案,使得总代价最小,也就是distance之和最小。
例如有如下4个编号:
aaaaaaa baaaaaa abaaaaa aabaaaa
显然的,第二,第三和第四编号分别从第一编号衍生出来的代价最小,因为第二,第三和第四编号分别与第一编号只有一个字母是不同的,相应的distance都是1,加起来是3。也就是最小代价为3。
问题可以转化为最小代价生成树的问题。因为每两个结点之间都有路径,所以是完全图。首先考虑用Kruskal算法解题,配合Disjoint Set Forest可以达到O(E lgV)。可是最后却无情的TLE了。分析TLE原因,原来K算法需要对所有边进行一次排序,当边数目比较多时,这就是非常耗时的一个工作。尤其本题是完全图,其代价可想而知。
具体实现如下:
#include <stdio.h>
#define SIZE 2012
int map[SIZE][SIZE];
char code[SIZE][10];
int main(){
int N;
int i,j,k,ans,diff,count,min,indexj;
int lowedge[SIZE];
while(scanf("%d",&N),N!=0){
//建图
for(i=0;i<N;i++)
scanf("%s",code[i]);
for(i=0;i<N;i++){
for(j=i;j<N;j++)
{
diff=0;
for(k=0;k<7;k++)
if(code[i][k]!=code[j][k]) diff++;
map[i][j]=map[j][i]=diff;
}
}
/* for(i=0;i<N;i++)
{
for(j=0;j<N;j++)
printf("%d ",map[i][j]);
printf("\n");
}
printf("Input Successs!\n");*/
ans=0;
//初始化flag[SIZE],adjacent[SIZE]
for(i=0;i<N;i++)
{
lowedge[i]=map[0][i];
//printf("%d ",lowedge[i]);
}
//printf("\n");
lowedge[0]=0;
count=N;
while(--count){
min=999;
for(j=0;j<N;j++)
if(lowedge[j]!=0&&lowedge[j]<min)
{ //edge[i]=0表示加入了TE中
min=lowedge[j];
indexj=j;
}
//printf("min=%d\n",min);
ans+=lowedge[indexj];
lowedge[indexj]=0;
for(j=0;j<N;j++)
if(lowedge[j]!=0&&map[indexj][j]<lowedge[j])
lowedge[j]=map[indexj][j];
/*printf("修改后的lowedge[i]:\n");
for(i=0;i<N;i++)
printf("%d ",lowedge[i]);
printf("\n");*/
}
printf("The highest possible quality is 1/%d.\n",ans);
}
return 0;
}