花了好长时间去理解题意,看来英语阅读能力还有待提高。
题意大概是这样的:用一个7位的string代表一个编号,两个编号之间的distance代表这两个编号之间不同字母的个数。一个编号只能由另一个编号“衍生”出来,代价是这两个编号之间相应的distance,现在要找出一个“衍生”方案,使得总代价最小,也就是distance之和最小。
例如有如下4个编号:
aaaaaaa
baaaaaa
abaaaaa
aabaaaa
显然的,第二,第三和第四编号分别从第一编号衍生出来的代价最小,因为第二,第三和第四编号分别与第一编号只有一个字母是不同的,相应的distance都是1,加起来是3。也就是最小代价为3。
问题可以转化为最小代价生成树的问题。因为每两个结点之间都有路径,所以是完全图。首先考虑用Kruskal算法解题,配合Disjoint Set Forest可以达到O(E lgV)。可是最后却无情的TLE了。分析TLE原因,原来K算法需要对所有边进行一次排序,当边数目比较多时,这就是非常耗时的一个工作。尤其本题是完全图,其代价可想而知。
以下是TLE版本:
继续探索Prime中。。。
参考链接:http://www.5ushare.com/bbs/redirect.php?fid=5&tid=46&goto=nextoldset
隔了好长时间,又回来做最小生成树了,这次把这题很轻松的AC了,用了PRIM算法配合手工优先权队列。
啊,发现当时自己好小白啊。
下面是AC代码:
/*=========================================
Prob :poj1789 Truck History
Type :最小生成树
Status:AC
Time :360MS
Memory:15636K
Author:myst
Remark:
==========================================*/
#include <iostream>
#define SIZ 2010
#define INF INT_MAX
using namespace std;
int N;
int map[SIZ][SIZ];
bool visited[SIZ];
int dis[SIZ];
//-------------priority queue----------------------
int heap_size;
int heap[SIZ];
int SWAP(int i, int j)
{
heap[i]^=heap[j];heap[j]^=heap[i];heap[i]^=heap[j];
return 0;
}
int MIN_HEAPIFY(int i)
{
int l=i<<1;
int r=(i<<1)+1;
int min;
if (l<=heap_size && dis[heap[l]]<dis[heap[i]]) min=l;
else min=i;
if (r<=heap_size && dis[heap[r]]<dis[heap[min]]) min=r;
if (min!=i){
SWAP(min, i);
MIN_HEAPIFY(min);
}
return 0;
}
int BUILD_HEAP()
{
for (int i=heap_size>>1;i>=1;i--)
MIN_HEAPIFY(i);
return 0;
}
int EXTRACT_MIN()
{
int min=heap[1];
SWAP(1, heap_size);
heap_size--;
return min;
}
//-------------------------------------------------
int MST_PRIM()
{
int ans=0;
for (int i=1;i<=N;i++){
dis[i]=INF;
visited[i]=0;
heap[i]=i;
}
dis[1]=0;
heap_size=N;
BUILD_HEAP();
while (heap_size>0){
int u=EXTRACT_MIN();//为减少操作,EXTRACT_MIN没有执行MIN_HEAPIFY,统一到下面BUILD_HEAP()一起执行。
visited[u]=1;
ans+=dis[u];
for (int j=1;j<=N;j++){
if (!visited[j] && map[u][j] && map[u][j]<dis[j])
dis[j]=map[u][j];
}
BUILD_HEAP();
}
return ans;
}
int main()
{
//freopen("in.txt", "r", stdin);
char code[SIZ][10];
while (scanf("%d", &N) && N){
for (int i=1;i<=N;i++)
scanf("%s", code[i]);
for (int i=1;i<=N-1;i++){
for (int j=i+1;j<=N;j++){
int dif=0;
for (int k=0;k<7;k++)
if (code[i][k]!=code[j][k]) dif++;
map[i][j]=dif;
map[j][i]=dif;
}
}
printf("The highest possible quality is 1/%d.\n", MST_PRIM());
}
return 0;
}
ENDProb :poj1789 Truck History
Type :最小生成树
Status:AC
Time :360MS
Memory:15636K
Author:myst
Remark:
==========================================*/
#include <iostream>
#define SIZ 2010
#define INF INT_MAX
using namespace std;
int N;
int map[SIZ][SIZ];
bool visited[SIZ];
int dis[SIZ];
//-------------priority queue----------------------
int heap_size;
int heap[SIZ];
int SWAP(int i, int j)
{
heap[i]^=heap[j];heap[j]^=heap[i];heap[i]^=heap[j];
return 0;
}
int MIN_HEAPIFY(int i)
{
int l=i<<1;
int r=(i<<1)+1;
int min;
if (l<=heap_size && dis[heap[l]]<dis[heap[i]]) min=l;
else min=i;
if (r<=heap_size && dis[heap[r]]<dis[heap[min]]) min=r;
if (min!=i){
SWAP(min, i);
MIN_HEAPIFY(min);
}
return 0;
}
int BUILD_HEAP()
{
for (int i=heap_size>>1;i>=1;i--)
MIN_HEAPIFY(i);
return 0;
}
int EXTRACT_MIN()
{
int min=heap[1];
SWAP(1, heap_size);
heap_size--;
return min;
}
//-------------------------------------------------
int MST_PRIM()
{
int ans=0;
for (int i=1;i<=N;i++){
dis[i]=INF;
visited[i]=0;
heap[i]=i;
}
dis[1]=0;
heap_size=N;
BUILD_HEAP();
while (heap_size>0){
int u=EXTRACT_MIN();//为减少操作,EXTRACT_MIN没有执行MIN_HEAPIFY,统一到下面BUILD_HEAP()一起执行。
visited[u]=1;
ans+=dis[u];
for (int j=1;j<=N;j++){
if (!visited[j] && map[u][j] && map[u][j]<dis[j])
dis[j]=map[u][j];
}
BUILD_HEAP();
}
return ans;
}
int main()
{
//freopen("in.txt", "r", stdin);
char code[SIZ][10];
while (scanf("%d", &N) && N){
for (int i=1;i<=N;i++)
scanf("%s", code[i]);
for (int i=1;i<=N-1;i++){
for (int j=i+1;j<=N;j++){
int dif=0;
for (int k=0;k<7;k++)
if (code[i][k]!=code[j][k]) dif++;
map[i][j]=dif;
map[j][i]=dif;
}
}
printf("The highest possible quality is 1/%d.\n", MST_PRIM());
}
return 0;
}