2016.08.17【初中部 NOIP提高组 】模拟赛C

第一题:

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.




第三题:
https://61.142.113.109/senior/#main/show/3078
题目描述:

【备战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,如果超过就继续枚举,没有超过就输出。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值