十连测d1T3

在比特镇一共有 n 个街区,编号依次为 1 到 n,它们之间通过若干条单向道路连接。
比特镇的交通系统极具特色,除了 m 条单向道路之外,每个街区还有一个编码 vali,不同街区可能
拥有相同的编码。如果 vali and valj = valj,即 vali 在二进制下与 valj 做与运算等于 valj,那么也会
存在一条额外的从 i 出发到 j 的单向道路。
Byteasar 现在位于 1 号街区,他想知道通过这些道路到达每一个街区最少需要多少时间。因为比特
镇的交通十分发达,你可以认为通过每条道路都只需要 1 单位时间。
Input
第一行包含两个正整数 n; m,表示街区的总数以及道路的总数。
第二行包含 n 个正整数 val1; val2; :::; valn,分别表示每个街区的编码。
接下来 m 行,每行包含两个正整数 ui; vi,表示一条单向道路,起点为 ui,终点为 vi。
Output
输出 n 行,每行一个整数,其中第 i 行输出到达第 i 个街区的最少时间,如果无法到达则输出 −1。
Examples
walk.in
5 2
5 4 2 3 7
1 4
2 3
walk.out
0
1
2
1
-1

思路:个人理解为一个二分图
val值: 1 2 3 ……….2^20-1 2^20 ——————(1)

n个点: 2^20+1 2^20+2 ……….2^20+n ———(2)

所有(2)向(1)建的边为1,所有(1)向(2)建的边为0
同时所有(1)在寻找过程中暴力枚举子集即可

program df;
type point=^node;
node=record
date,ends:longint;
next:point;
end;
tttt=array[0..2000000] of point;
var i,n,m,x,y,z,k,t,h:longint;
path,pa:tttt; j:point; // path指的是连接长度为1的,pa指的是连接长度为0的
a,d,q:array[0..2000000] of longint;
b:array[0..2000000] of boolean;
procedure com(x,y:longint; var a:tttt);
var i:point;
begin
i:=a[x];
new(a[x]);
a[x]^.ends:=y;
a[x]^.next:=i;
end;

procedure deal(x,y:longint);
var i:point;
j:longint;
begin
if d[x]>=0 then exit;
inc(t);
q[t]:=x; //入队
d[q[t]]:=y;
i:=pa[x];
while i<>nil do
begin
j:=i^.ends;
deal(j,y); //所有当前val值能到达的点都与当前的点权值相同
i:=i^.next;
end;
if x>=z then exit; //如果超过val值的最大范围就不属于val值,同样没必要找子集
for j:=1 to 20 do
if x>>(j-1) and 1=1 then deal(x xor (1<<(j-1)),y); //每一位为1的都取反(即子集)
end;

begin
assign(input,’walk.in’);
reset(input);
assign(output,’walk.out’);
rewrite(output);
readln(n,m);
z:=1<<20; //将1到2^20 作为val值,n个点排到2^20+1到2^20+n
for i:=1 to n do
begin
read(x);
com(i+z,x,path); //第i个点向val值为x的点连接一条为1的边
com(x,i+z,pa); //val值为x的点向能到的点连接一条为0的边
end;
for i:=1 to m do
begin
readln(x,y);
com(x+z,y+z,path); //x,y间直接建边
end;

for i:=1 to n+z do
d[i]:=-1;
h:=1; t:=0;
deal(z+1,0); //从第一个点出发
while h<=t do
begin
x:=q[h];
j:=path[x];
while j<>nil do
begin
deal(j^.ends,d[x]+1); // x点到达的点距离加+1
j:=j^.next;
end;
inc(h);
end;
for i:=z+1 to z+n do
writeln(d[i]);

close(input);
close(output);
end.

转载于:https://www.cnblogs.com/Gxyhqzt/p/7784226.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值