h1n1

H1N1(h1n1)
题目描述
H1N1来势汹汹,一个区域内的城镇要共同抵御疫情……
这个区域内共有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
6
0 1 0
1 0 0
0 0 0
样例输出
1
注释
【样例解释】
城镇1已建好防疫站,且1-2有道路已经修好。只需在城镇3建防疫站,花费1.
【数据范围】
对于100%的数据
N<=700
0<=Q,P<=N
Cost,price 均为 1-100000 间的整数,题目保证P+Q>0
对于 20% 的数据 P=0,Q=1
对于 30% 的数据 N<=10

构建一个超级源点
如果某一个点已经建好防疫站,则它向源点连一条权值为0的边
某一条路已经建好,则两点之间连一条权值为0的边
某个点可以建防疫站,从它向源点连一条权值为建造价格的边
某条路可以建,两点间连一条权值为建造价格的边
求最小生成树

code:
var i,j,k:longint;
n,p,q:longint;
edge:array[1..600000]of record
s,t,v:longint;
end;
map:array[1..5000,1..5000]of longint;
father:array[0..5000]of longint;
num:longint;
ans,ingraph:longint;
function find(x:longint):longint;
begin if father[x]=x
then exit(x)
else exit(find(father[x]));
end;
procedure union(x,y:longint);
begin father[find(x)]:=find(father[y]);
end;
procedure qsort(x,y:longint);
var head,tail:longint;
k,temp:longint;
begin head:=x; tail:=y;
k:=edge[(head+tail) div 2].v;
while head<=tail do
begin while edge[head].v<k do inc(head);
while k<edge[tail].v do dec(tail);
if head<=tail
then begin temp:=edge[head].s;
edge[head].s:=edge[tail].s;
edge[tail].s:=temp;
temp:=edge[head].t;
edge[head].t:=edge[tail].t;
edge[tail].t:=temp;
temp:=edge[head].v;
edge[head].v:=edge[tail].v;
edge[tail].v:=temp;
inc(head);
dec(tail);
end;
end;
if head<y then qsort(head,y);
if x<tail then qsort(x,tail);
end;
begin 
fillchar(edge,sizeof(edge),0);
num:=0;
readln(n,q,p);
for i:=1 to q do
begin read(k);
inc(num);
edge[num].s:=0;
edge[num].t:=k;
edge[num].v:=0;
end;
for i:=1 to p do
begin read(j,k);
inc(num);
edge[num].s:=0;
edge[num].t:=j;
edge[num].v:=k;
end;
for i:=1 to n do
for j:=1 to n do
read(map[i,j]);
for i:=1 to n do
for j:=1 to n do
begin read(k);
if k=1
then begin map[i,j]:=0;
inc(num);
edge[num].s:=i;
edge[num].t:=j;
edge[num].v:=0;
end;
end;
for i:=1 to n do
for j:=1 to n do
if map[i,j]<>0
then begin inc(num);
edge[num].s:=i;
edge[num].t:=j;
edge[num].v:=map[i,j];
end;
qsort(1,num);
fillchar(father,sizeof(father),0);
for i:=0 to n do
father[i]:=i;
ingraph:=0; i:=0; ans:=0;
while ingraph<n do
begin inc(i);
if find(edge[i].s)<>find(edge[i].t)
then begin inc(ingraph);
inc(ans,edge[i].v);
union(edge[i].s,edge[i].t);
end;
end;
writeln(ans);

end.


原文地址:https://www.cnblogs.com/spiderKK/p/4893700.html