【最小生成树】传染病防疫

来源:互联网 发布:照片审核处理工具 mac 编辑:程序博客网 时间:2024/05/01 12:09

传染病防疫

 

题目描述

传染病来势汹汹,一个区域内的城镇要共同抵御疫情……

这个区域内共有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点组成的图的最小生成树,得出总费用,即为最小花费。

      有了思路代码也就不难写出来了。


程序:

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.

0 0
原创粉丝点击