瓜农王大爷去年种西瓜赚了不少钱。看到收入不错,今年他又重新开辟了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;
}
写在最后:我还有一种思路但没有实现,不知道是否,首先找出必须要打井的地。必须打井的地是这样判断的:如果这块地与其他地修管道的代价都大于在这块地打井的费用,那么这块地必须要打井。
找出必须要打井的地后,判断最小打井代价的地时候已经打井,如果没有打井,就打井,然后用普利姆算法进行循环,