5 <= N <= 10000,N-1 <= P <= 100000,0 <= Lj <= 1000,1 <= Ci <= 1,000。
首先这个题是最小生成树问题,但是没有现成的生成树,所以我们就先构造一个。对于每条边,如果选的话,则要耗去来回一趟和访问2个端点所用的的时间总合,所以将图中各个边的权值改为边本来的权值的两倍加上访问两端点的值,这样一棵树就构造好。至于住在哪间房里面,选择Ci最小的那一间就可以了。
接下来就是运用最小生成树的算法,在我用kruscal算法的过程中,也发现了我以前写这个算法的一个错误,虽然花了我很多时间去找这个错误。。。但是以后肯定是不会再错了,总之这道题还是很有收获的。
#include
#include
struct node
{
int x, y;
int w;
};
node s[100010];
int l, sum;
int f[10010];
int talk[10010];
void init()
{
int i;
for(i = 0; i < 10010; i++)
f[i] = i;
}
int cmp(const void *a, const void *b)
{
return (((node *)a)->w - ((node *)b)->w);
}
void kruscal(int n)
{
int q;
qsort(s, l, sizeof(s[0]), cmp);
int num = 1, i, j;
int k = 0;
while(num < n)
{
if(f[s[k].x] != f[s[k].y])
{
num++;
sum += s[k].w;
//printf("%d - %d = %d, sum = %d\n", s[k].x, s[k].y, s[k].w, sum);
q = f[s[k].y];
for(j = 1; j <= n; j++)
{
if(f[j] == q)//之前这里写的是if(f[j] == f[s[k].y]),结果都是WA
f[j] = f[s[k].x];
}
}
k++;
}
}
int main (void)
{
int n, p, i;
while(scanf("%d %d", &n, &p) != EOF)
{
init();
l = 0;
sum = 0;
int min = 9999;
for(i = 1; i <= n; i++)
{
scanf("%d", &talk[i]);
if(min > talk[i])
min = talk[i];
}
int temp;
for(i = 0; i < p; i++)
{
scanf("%d %d %d", &s[l].x, &s[l].y, &temp);
s[l].w = talk[s[l].x] + talk[s[l].y] + 2 * temp;
l++;
}
/*
for(i = 0; i < l; i++)
printf("%d ", s[i].w);
printf("\n");
*/
kruscal(n);
printf("%d\n", sum + min);
/*
printf("----------------------------\n");
for(i = 0; i < l; i++)
{
printf("%d - %d = %d\n", s[i].x, s[i].y, s[i].w);
}
*/
}
return 0;
}