习题:传染病防疫(最小生成树)
传染病防疫
【题目描述】
传染病来势汹汹,一个区域内的城镇要共同抵御疫情……
这个区域内共有N座城镇,其中Q个城镇已经建好了防疫站,为了防疫工作的需要,每个城镇必须有公路通到至少一个防疫站,现在已有一些修好的路可以利用。修建第i个城镇到第j个城镇的公路花费cost(i,j),还有有P个城镇由于条件优越,可以花钱建防疫站。这N个城镇的人民找到了会编程的你,至少要花多少钱可以完成防疫?
【输入格式】
第1行: 3个整数 N,Q,P
下来Q行,每行一个整数Ki,表示第K个城镇已有防疫站,
下来P行,每行2个整数Ti和price_i,
表示在第Ti个城镇修建防疫站的价格为price_i
以下N*N的矩阵,第i行第j列的整数 表示cost(i,j)
最后N*N的矩阵,第i行第j列的整数第i个城镇与第j个城镇之间的道路有无情况,为0或者1,1表示已经修建好的,0表示还没有道路。
题目保证2个矩阵都是对称的(a[i,j]= a[j,i])且主对角线都为0
(a[i,i]=0 , i=1..n)。
【输出格式】
1行 1个整数ans,表示最少的花费。
【输入样例】
3 1 1
1
3 1
0 3 3
3 0 5
3 5 0
0 1 0
1 0 0
0 0 0
【输出样例】
1
【样例解释】
城镇1已建好防疫站,且1-2有道路已经修好。
只需在城镇3建防疫站,费用为1.
【数据范围】
对于 20% 的数据 P=0,Q=1
对于 30% 的数据 N<=10
对于100%的数据 N<=700
0<=Q,P<=N Cost,price 均为 1~100000 间的整数,题目保证P+Q>0
分析:
看到题目后会感觉无从下手,但分析后可以发现,当只有一个防疫站,切不能建造新防疫站时,本题可以用最小生成树解决。但本题有多个防疫站,且防疫站还可以建造,那这该怎么办呢?
当然还是使用最小生成树,但不是裸的。我们应该换一种思路,不要把防疫站放在一些点上弄出许多防疫站,而是单独作为一个点“0”。这个点表示防疫站,如果某城镇本来就有一个防疫站,我们就将这个城镇的对应点同0点连一条权值为0的无向边;如果某城镇可以建防疫站,也连一条边,但权值为修建的费用;其他点之间的边的权值为修路的费用,这样问题就迎刃而解了,接下来求0..n点组成的图的最小生成树,得出总费用,即为最小花费。
有了思路代码也就不难写出来了。
程序:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
program epidemic; var a:array[0..4000,0..4000]of int64; f:array[0..4000]of int64; c:array[0..4000]of 0..1; n,i,m,j,k,x,y,q,p,s:longint; begin assign(input,'epidemic.in'); reset(input); assign(output,'epidemic.out'); rewrite(output); readln(n,q,p); fillchar(a,sizeof(a),$7f); for i:=1 to q do begin read(x); a[x,0]:=0; a[0,x]:=0; end; readln; for i:=1 to p do begin read(x); read(y); a[x,0]:=y; a[0,x]:=y; end; readln; for i:=1 to n do begin for j:=1 to n do begin read(a[i,j]);if a[i,j]=0 then a[i,j]:=maxlongint; end; readln; end; for i:=1 to n do begin for j:=1 to n do begin read(x); if x=1 then a[i,j]:=0; end;//建图 end; fillchar(f,sizeof(f),$7f); f[0]:=0; for i:=1 to n+1 do begin k:=-1; for j:=0 to n do if (c[j]=0)and(f[j]<f[k]) then k:=j; c[k]:=1; for j:=0 to n do if (c[j]=0)and(a[k,j]<f[j]) then f[j]:=a[k,j]; end; for i:=0 to n do s:=s+f[i];//求最小生成树权值和 writeln(s); close(input); close(output); end.