POJ 1789--Truck History(最小生成树)

本文探讨了最小生成树的概念及其在Prim算法中的应用,通过两种实现方式深入解析算法逻辑,包括朴素做法和利用队列优化的方法。重点强调了贪心策略在寻找最优连接路径中的作用。

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

本题要求最小生成树,因为已经是最大团,建议采用prim算法。
Prim算法实质为贪心思想,每次我们只选择一个到已加入生成树集合的点距离最近的点即可,且每加入一个新点都要更新其他点的最短距离。
最朴素的做法,设置一个是否在生成树集合的bool数组以及一个标志点到生成树的最小距离的数组,每次加入新点,更新最小距离时,且可以直接找出下一个加入的点。

另一种做法:因为本题距离只在1到7之间,想用类似hash的思想,设置7个队列,把最小距离为i的点直接放进队列q[i]中,这样每次从1到7遍历队列,遇到第一个没在生成树的点就说明此点位下一个加入生成树中的点,但是因为当最小距离更新时,我们不能删除这个点在较大距离的队列中的元素,所以有很多冗余,效果不理想。


Prim:

#include<cstdio>
#include<cstring>
#define maxN 2001
#define maxL 8
#define INF 0X7F7F7F7F

int truckNum;
char truckCode[maxN][maxL];

char typeDis(int x,int y)
{
    char dis = 0;
    for(int i = 0;i < maxL-1;i++)
    {
        if(truckCode[x][i] != truckCode[y][i])
            dis++;
    }
    return dis;
}

int search_Prim()
{
    int i,j;
    char truckDis[maxN];     //保存卡车到已加入生成树中的卡车最小距离
    char IsInTree[maxN];
    int minTrucknextTruck;
    int tmpDis,sumDis,minDis;
    sumDis = 0;
    memset(IsInTree,0,sizeof(IsInTree));
    memset(truckDis,0X7F,sizeof(truckDis));
    nextTruck = 0;
    for(i = 1;i < truckNum;i++)
    {
        minTruck = nextTruck;
        IsInTree[minTruck] = true;
        minDis = INF;
        for(j = 1;j < truckNum;j++)
        {
            if(!IsInTree[j])
            {
                tmpDis = typeDis(minTruck,j);
                if(truckDis[j] > tmpDis)      //更新最小距离
                    truckDis[j] = tmpDis;
                if(truckDis[j] < minDis)      //从不在生成树中的点选择下一个加入树中的点
                {
                    minDis = truckDis[j];
                    nextTruck = j;
                }
            }
        }
        sumDis += minDis;
    }
    printf("The highest possible quality is 1/%d.\n",sumDis);
    return 0;
}

int main()
{
    while(scanf("%d",&truckNum)&&truckNum)
    {
        getchar();
        for(int i = 0;i < truckNum;i++)
            gets(truckCode[i]);
        search_Prim();
    }
    return 0;
}


Prim&Queue:

#include<cstdio>
#include<cstring>
#define maxN 2001
#define maxL 8
#define INF 0X7F7F7F7F
#define qSize  2000

int truckNum;
char truckCode[maxN][maxL];

class queue_self
{
    short q[qSize+1];
    int qHead;
    int qTail;
public:
    queue_self():qHead(0),qTail(0){}
    void enQueue(int x)
    {
        q[qTail] = x;
        if(qTail == qSize)
            qTail = 0;
        else qTail++;
    }
    short deQueue()
    {
        short x = q[qHead];
        if(qHead == qTail)
            qHead = 0;
        else qHead++;
        return x;
    }
    bool empty()
    {
        if(qHead == qTail)
            return true;
        else return false;
    }
};

char typeDis(int x,int y)
{
    char dis = 0;
    for(int i = 0;i < maxL-1;i++)
    {
        if(truckCode[x][i] != truckCode[y][i])
            dis++;
    }
    return dis;
}

int search_Prim()
{
    int i,j;
    char truckDis[maxN];
    char IsInTree[maxN];
    int minTruck;
    int minDis,tmpDis,sumDis;
    char IsFindMin;
    queue_self q[maxL];
    sumDis = 0;
    memset(IsInTree,0,sizeof(IsInTree));
    memset(truckDis,0X7F,sizeof(truckDis));
    truckDis[0] = 1;
    q[1].enQueue(0);
    for(i = 0;i < truckNum;i++)
    {
        IsFindMin = false;
        for(minDis = 1;minDis < maxL;minDis++)
        {
            while(!q[minDis].empty())
            {
                j = q[minDis].deQueue();
                if(!IsInTree[j])
                {
                    minTruck = j;
                    IsFindMin = true;
                    break;
                }
            }
            if(IsFindMin)
                break;
        }
        sumDis += minDis;
        IsInTree[minTruck] = true;
        for(j = 1;j < truckNum;j++)
        {
            if(!IsInTree[j])
            {
                tmpDis = typeDis(minTruck,j);
                if(truckDis[j] > tmpDis)
                {
                    truckDis[j] = tmpDis;
                    q[tmpDis].enQueue(j);
                }
            }
        }
    }
    printf("The highest possible quality is 1/%d.\n",sumDis-1);
    return 0;
}

int main()
{
    while(scanf("%d",&truckNum)&&truckNum)
    {
        getchar();
        for(int i = 0;i < truckNum;i++)
            gets(truckCode[i]);
        search_Prim();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值