poj1789 Truck History

本文通过解决一个具体的字符串编号问题,介绍了如何使用Kruskal算法和Prim算法来寻找最小生成树,并对比了两种算法在完全图场景下的表现。

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

花了好长时间去理解题意,看来英语阅读能力还有待提高。

题意大概是这样的:用一个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版本:

ContractedBlock.gif ExpandedBlockStart.gif Code
 1 //关键字:Disjoint-set, minimal spanning tree: Kruskal, prime
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #define MAX 2000
 5 typedef struct{
 6     int rank;
 7     int parent;
 8     char string[7];
 9 }VERTEX;
10 VERTEX vertex[MAX];
11 int distance[MAX][MAX];
12 int sortDis[MAX*(MAX-1)/2];
13 //--------------------DisJoint Set Operations----------------
14 void MakeSet(VERTEX *v, int x)
15 {
16     v[x].rank=0;
17     v[x].parent=x;
18 }
19 int FindSet(VERTEX *v, int x)
20 {
21     if (x != v[x].parent)
22         v[x].parent=FindSet(v, v[x].parent);
23     return v[x].parent;
24 }
25 void Link(VERTEX *v, int x, int y)
26 {
27     if (v[x].rank > v[y].rank)
28         v[y].parent=x;
29     else{
30         v[x].parent=y;
31         if (v[x].rank==v[y].rank)
32             v[y].rank++;
33     }
34 }
35 void Union(VERTEX *v, int x, int y)
36 {
37     Link(v, FindSet(v, x), FindSet(v, y));
38 }
39 
40 //------------------------------------------------------------
41 int cmp(const void *a, const void *b)
42 {
43     return (distance[(*(int *)a)/MAX][(*(int *)a)%MAX] >= distance[(*(int *)b)/MAX][(*(int *)b)%MAX]) ? 1-1;
44 }
45 main()
46 {
47     int n, i, j, k, dif, eageCount=-1, Q, va, vb;
48     VERTEX *v;
49     v=vertex;
50     //freopen("input.txt", "r", stdin);
51     while (scanf("%d"&n) && n!=0){
52         //输入字符串并构造不相交集的最小集
53         for (i=0; i<n; i++){
54             scanf("%s\n", (v+i)->string);
55             MakeSet(v, i);
56         }
57         //计算字符串中不同字符的个数,保存到distance[][],
58         //distance[][]二维数组只用到上右半个三角区域
59         for (i=0; i<n-1; i++){
60             for (j=i+1; j<n; j++){
61                 eageCount++;
62                 dif=0;
63                 for (k=0; k<7; k++){
64                     if ((v+i)->string[k] != (v+j)->string[k]){
65                         dif++;
66                     }
67                 }
68                 distance[i][j]=dif;
69                 sortDis[eageCount]=i*MAX+j;
70             }
71         }
72         //对distance[][]进行从小到大的排序,排序结构保存到sortDis[]当中
73         qsort(sortDis, eageCount+1sizeof(int), cmp);
74         //Kruskal算法
75         Q=0;
76         for (i=0; i<=eageCount; i++){
77             va=sortDis[i]/MAX;
78             vb=sortDis[i]%MAX;
79             if (FindSet(v, va) != FindSet(v, vb)){
80                 Union(v, va, vb);
81                 Q+=distance[va][vb];
82             }    
83         }
84         printf("The highest possible quality is 1/%d.\n", Q);
85     }
86 }

继续探索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 ;
}
END

转载于:https://www.cnblogs.com/zen_chou/archive/2009/04/04/1429465.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值