第一题:
https://61.142.113.109/senior/#main/show/3076
题目描述:
【备战NOIP2012图论专项模拟试题】位图 (Standard IO)
给出一个大小为n行*m列的矩形位图。该位图的每一个象素点不是白色就是黑色,但是至少有一个象素点是白色。在i行j列的象素点我们称为点(i,j)。两个象素点p1=(i1,j1)和p2=(i2,j2)之间的距离定义如下:
d(p1,p2)=|i1-i2|+|j1-j2|
现在的任务是:对于每一个象素点,计算它到最近的白色点的距离。如果它本身是白色点,距离为0。
Input
【输入格式】
第1行:2个整数n,m(1<=n <=182,1<=m<=182)
接下来n行,每一行有一个长度为m的0/1字符串,描述一行象素点。如果点(i,j)为白色,则值为1,否则值为0。
Output
【输出格式】
共n行,每行有m个整数,数之间用1个空格分开,分别表示对应的象素点距离白色点的距离。
Sample Input
3 4
0001
0011
0110
Sample Output
3 2 1 0
2 1 0 0
1 0 0 1
很水的一道题,
和以前做的https://61.142.113.109/senior/#main/show/1445这题很像
首先把所有白点存进队列里,
对于队列里每个数,把它上下左右赋值为它的值+1,
如果它上下左右已经有值就不用再往下赋值了,
就这样宽搜以此类推
参考程序:
var n,m,i,j,k,x,y:longint;
a:array[0..200,0..200]of char;
f,bz:array[0..200,0..200]of longint;
b:array[0..40000,1..2]of longint;
data:array[1..100000,1..3]of longint;
f1:array[1..4]of longint=(-1,0,1,0);
f2:array[1..4]of longint=(0,1,0,-1);
begin
readln(n,m);
for i:=1 to n do
begin
for j:=1 to m do
begin
read(a[i,j]);
if a[i,j]='1' then
begin
inc(b[0,1]);
b[b[0,1],1]:=i;
b[b[0,1],2]:=j;
end;
end;
readln;
end;
for i:=1 to b[0,1] do
begin
data[i,1]:=b[i,1];
data[i,2]:=b[i,2];
bz[b[i,1],b[i,2]]:=1;
end;
i:=0;
j:=b[0,1];
while i<j do
begin
inc(i);
for k:=1 to 4 do
begin
x:=data[i,1]+f1[k];
y:=data[i,2]+f2[k];
if(x>0)and(x<=n)and(y>0)and(y<=m)and(bz[x,y]=0)then
begin
inc(j);
data[j,1]:=x;
data[j,2]:=y;
data[j,3]:=data[i,3]+1;
f[x,y]:=data[j,3];
bz[x,y]:=1;
end;
end;
end;
for i:=1 to n do
begin
for j:=1 to m do write(f[i,j],' ');
writeln;
end;
end.
第二题:
https://61.142.113.109/senior/#main/show/3077
题目描述:
【备战NOIP2012图论专项模拟试题】外星人入侵 (Standard IO)
外星人入侵地球。可怕的吃人外星人正在全国各地依次序建立它们的基地。
全国共有N(1≤ N ≤10,000)座城市,城市编号1~N。城市之间有M(0≤ M ≤100,000)条双向道路相连。外星人计划建立A(0≤A≤N)个基地。
你只有在距离当前所有外星人基地至少K(1≤K≤100)单位长度的城市才能得到安全。
所以你必须赶快写一个程序决定走到哪里去。
Input
第1行:4个整数N, M, A, K
接下来M行,每行3个整数T1, T2(1≤T1<T2≤N)和D(1≤D≤100),表示城市T1与T2之间有一条长度为D的道路。两个城市之间最多有一条直连道路。
接下来A行,每行1个整数Bi(1≤Bi≤N),表示外星人依次序建的第i个基地所在的城市编号。
Output
共A行,第i行1个整数,表示当外星人建好第i个基地后,距离当前所有基地B1,B2,...,Bi至少K长度的城市的数量。
Sample Input
7 6 3 3
1 2 1
1 3 1
2 5 1
3 6 1
1 4 1
4 7 2
2
1
4
Sample Output
2
1
0
这题我还是用暴力宽搜,
对于一个新建立的基地,枚举它能够到达的城市,
如果能够对这个城市产生威胁,那么这个城市就不能再居住,
之后再往下枚举,以此类推
这里有个优化,就是当前安全城市数为0时,
以后每个时间段的安全城市数一定就是0了,直接输出就好了
参考程序:
var n,m,a,k,x,y,t,i,j,ans:longint;
f,f2:array[1..10000,0..2000]of 0..10000;
bz:array[1..10000]of longint;
data:array[1..50000,1..2]of longint;
procedure bfs;
var l,r,i,t:longint;
begin
l:=0;
r:=1;
while l<r do
begin
inc(l);
t:=data[l,1];
for i:=1 to f[t,0] do
begin
if (bz[f[t,i]]>data[l,2]+f2[t,i])
and(data[l,2]+f2[t,i]<k) then
begin
if bz[f[t,i]]=maxlongint then dec(ans);
bz[f[t,i]]:=data[l,2]+f2[t,i];
inc(r);
data[r,1]:=f[t,i];
data[r,2]:=data[l,2]+f2[t,i];
end;
end;
end;
end;
begin
readln(n,m,a,k);
for i:=1 to m do
begin
readln(x,y,t);
inc(f[x,0]);
f[x,f[x,0]]:=y;
inc(f[y,0]);
f[y,f[y,0]]:=x;
f2[x,f[x,0]]:=t;
f2[y,f[y,0]]:=t;
end;
for i:=1 to n do bz[i]:=maxlongint;
ans:=n;
for i:=1 to a do
begin
readln(x);
data[1,1]:=x;
data[1,2]:=0;
if bz[x]=maxlongint then dec(ans);
bz[x]:=0;
bfs;
writeln(ans);
if ans=0 then
begin
for j:=i+1 to a do writeln(0);
break;
end;
end;
end.
第三题:
【备战NOIP2012图论专项模拟试题】无线通讯网 (Standard IO)
国防部计划用无线网络连接若干个边防哨所。2种不同的通讯技术用来搭建无线网络:每个边防哨所都要配备无线电收发器;有一些哨所还可以增配卫星电话。
任意两个配备了一条卫星电话线路的哨所均可以通话,无论它们相距多远。而只通过无线电收发器通话的哨所之间的距离不能超过D,这是受收发器的功率限制。收发器的功率越高,通话距离D会更远,但同时价格也更贵。
收发器需要统一购买和安装,所以全部哨所只能选择安装一种型号的收发器。换句话说,每一对哨所之间的通话距离都是同一个D。
你的任务是确定收发器必须的最小通话距离D,使得每一对哨所之间至少有一条通话路径(直接的或者间接的)。
Input
第1行:2个整数S(1 <= S <= 100)和P(S < P <= 500),S表示可安装的卫星电话的线路数,P表示边防哨所的数量。
接下来P行,每行描述一个哨所的平面坐标(x,y),以km为单位,整数,0<=x,y<=10,000
Output
第1行:1个实数D,表示无线电收发器的最小传输距离。精确到小数点后2位。
Sample Input
2 4
0 100
0 300
0 600
150 750
Sample Output
212.13
有P个节点,且每个节点都可以到达其它的节点,求第P-S长的边的长度。
这题要用最小生成树算法,
参考程序:
var n,m,i,j,lenb,t:longint;
b:array[0..500000] of real;
a,c:array[0..250000,0..2] of longint;
f:array[0..500000] of longint;
procedure kuaipai(l,r:longint);
var i,j:longint;
mid:real;
begin
i:=l;
j:=r;
mid:=b[r];
while i<=j do
begin
while b[i]<mid do inc(i);
while b[j]>mid do dec(j);
if i<=j then
begin
b[0]:=b[i];
b[i]:=b[j];
b[j]:=b[0];
c[0]:=c[i];
c[i]:=c[j];
c[j]:=c[0];
inc(i);
dec(j);
end;
end;
if i<r then kuaipai(i,r);
if l<j then kuaipai(l,j);
end;
function getfather(x:longint):longint;
begin
if f[x]=0 then exit(x);
f[x]:=getfather(f[x]);
exit(f[x]);
end;
begin
readln(m,n);
for i:=1 to n do
readln(a[i,1],a[i,2]);
for i:=1 to n-1 do
for j:=i+1 to n do
begin
inc(lenb);
b[lenb]:=sqrt(sqr(a[i,2]-a[j,2])+sqr(a[i,1]-a[j,1]));
c[lenb,1]:=i;
c[lenb,2]:=j;
end;
kuaipai(1,lenb);
for i:=1 to lenb do
begin
if getfather(c[i,1])<>getfather(c[i,2]) then
begin
f[getfather(c[i,1])]:=getfather(c[i,2]);
inc(t);
if t=n-m then
begin
writeln(b[i]:0:2);
exit;
end;
end;
end;
end.
第四题:
https://61.142.113.109/senior/#main/show/3079
题目描述:
【备战NOIP2012图论专项模拟试题】砍树 (Standard IO)
给出一个树形图("tree-shaped" network),有N(1 <= N <= 10,000)个顶点。如果删除树上某一个顶点,整棵树就会分割成若干个部分。显然,每个部分内部仍保持连通性。
现在问:删除哪个点,使得分割开的每个连通子图中点的数量不超过N/2。如果有很多这样的点,就按升序输出。
例如,如图所示的树形图,砍掉顶点3或者顶点8,分割开的各部件。
Input
第1行:1个整数N,表示顶点数。顶点编号1~N
第2..N行:每行2个整数X和Y,表示顶点X与Y之间有一条边
Output
若干行,每行1个整数,表示一个符合条件的顶点的编号。如果没有顶点符合条件,则仅在第1行上输出"NONE"
Sample Input
10
1 2
2 3
3 4
4 5
6 7
7 8
8 9
9 10
3 8
Sample Output
3
8
我们先从第一个位置进行一次DFS,之后记录下以当前节点为根节点时的子节点数量
之后枚举断开的位置,
当子树的根的父亲是断掉点的儿子或断掉点本身,则直接加上子树根的答案.
记录答案之后直接判断是否<=n div 2并且所有节点数量-这个点的子节点数量<=n div 2就输出
参考程序:
var a:array[1..10000,0..1000]of longint;
f,bz,bz2:array[1..10000]of longint;
i,j,x,y,n:longint;
procedure dfs(x:longint);
var i:longint;
begin
bz[x]:=1;
if a[x,0]=0 then
begin
f[x]:=1;
exit;
end;
for i:=1 to a[x,0] do
begin
if bz[a[x,i]]=1 then continue;
dfs(a[x,i]);
f[x]:=f[x]+f[a[x,i]];
if f[a[x,i]]>n div 2 then bz2[x]:=1;
end;
f[x]:=f[x]+1;
if n-f[x]>n div 2 then bz2[x]:=1;
end;
begin
readln(n);
for i:=1 to n-1 do
begin
readln(x,y);
inc(a[x,0]);
a[x,a[x,0]]:=y;
inc(a[y,0]);
a[y,a[y,0]]:=x;
end;
dfs(1);
for i:=1 to n do
if bz2[i]=0 then writeln(i);
end.
我们先从第一个位置进行一次DFS,之后记录下以当前节点为根节点时的节点数量(即把当前节点下的子树的节点数量加起来再加上自己本身)。
之后枚举断开的位置,如果断开之后的图节点大于当前节点的结果,就把它变成(N-节点数)。
再判断有没有超过N div 2,如果超过就继续枚举,没有超过就输出。