杭州电子科技大学2018研究生计算机复试王大爷卖瓜

瓜农王大爷去年种西瓜赚了不少钱。看到收入不错,今年他又重新开辟了n个西瓜地。 
为了能给他的n个西瓜地顺利的浇上水,对于每个西瓜地他可以选择在本地打井,也可以修管道从另一个瓜地(这个瓜地可能打了井;也可能没打井,他的水也是从其他瓜地引来的)将水引过来。 
当然打井和修管道的费用有差别。已知在第i个西瓜地打井需要耗费wi元,在第i、j个西瓜地之间修管道需要耗费pi,j元。 
现在的问题是:王大爷要想使所有瓜地都被浇上水,至少需要花费多少钱(打井与修管道的费用和)? 
由于瓜地较多,王大爷无法选择在哪些(个)瓜地打井,哪些西瓜地之间修管道。 
请你编程帮王大爷做出决策,求出最小费用。

输入格式

第1行,一个正整数n,代表西瓜地的数量。 
以下n行,依次给出整数w1..wn(每块西瓜地的打井费用)。 
紧接着是一个n*n的整数矩阵,矩阵的第i行第j列的数代表pi,j(两块西瓜地之间建立管道的费用)。每行的两个数之间有一个空格隔开。

这道题和落谷OJ上的p1550题一样https://www.luogu.org/problemnew/show/p1550

思路:利用普利姆算法构造最小生成树,首先选一块打井费用最小的地进行打井,然后更新closege数组,closege[i]中对应的数字表示的含义为一块地通过修管道所要耗费的最小代价。每次循环从closege数组总选择一个最小的数字,此最小数字对应的下标为那一块地,判断这块地是打井的代价和修管道的代价那个大,选择一个最小的代价,然后更新closege数组,进行n-1此循环。

#include <cstdio>
#include <cstring>
int cost[305];
bool flag_water[305];
int number[305][305];
int closege[305];
int query_min_cost(int n)
{
    int min,i,min_location;
    for(i=0;flag_water[i]!=false;i++);
    min=closege[i];
    min_location=i;
    for(;i<n;i++)
    {
        if(!flag_water[i]&&min>closege[i])
        {
            min=closege[i];
            min_location=i;
        }
    }
    return min_location;

}
void change_closege(int i,int n)
{
    for(int j=0;j<n;j++)
    {
        if(!flag_water[j]&&number[i][j]<closege[j])
        {
            closege[j]=number[i][j];
        }
    }
}
int main()
{
   // FILE *f=fopen("luogu.txt","r");
    memset(flag_water,false,sizeof(flag_water));
    int n;
    scanf("%d",&n);
    //fscanf(f,"%d",&n);
    for(int i=0;i<n;i++)
     {
        scanf("%d",&cost[i]);
        //fscanf(f,"%d",&cost[i]);
        closege[i]=cost[i];
     }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
           // fscanf(f,"%d",&number[i][j]);
            scanf("%d",&number[i][j]);
        }
    }
    int min_cost=cost[0],min_location=0;
    for(int i=0;i<n;i++)
    {
        if(min_cost>cost[i])
        {
            min_cost=cost[i];
            min_location=i;
        }
    }
    int ans_cost=min_cost;
    flag_water[min_location]=true;
   // printf("%d  %d\n",ans_cost,min_location);
    for(int i=0;i<n;i++)
    {
        if(!flag_water[i]&&closege[i]>number[min_location][i])
        {
            closege[i]=number[min_location][i];
        }
        //printf("%d  ",closege[i]);
    }
    //printf("\n");
    for(int i=1;i<n;i++)
    {
        int k=query_min_cost(n);
        //printf("%d  ",k);
        if(cost[k]<closege[k])
        {
            ans_cost+=cost[k];
        }
        else
        {
            ans_cost+=closege[k];
        }
        flag_water[k]=true;
        change_closege(k,n);
    }
    printf("%d\n",ans_cost);
    return 0;
}

写在最后:我还有一种思路但没有实现,不知道是否,首先找出必须要打井的地。必须打井的地是这样判断的:如果这块地与其他地修管道的代价都大于在这块地打井的费用,那么这块地必须要打井。

找出必须要打井的地后,判断最小打井代价的地时候已经打井,如果没有打井,就打井,然后用普利姆算法进行循环,

猜你喜欢

转载自blog.csdn.net/LYGliyaogang/article/details/88344993