您的位置:首页 > 其它

Bzoj2595: [Wc2008]游览计划

2016-09-13 11:17 387 查看
原题网址:http://www.lydsy.com/JudgeOnline/problem.php?id=2595

标算是斯坦纳树,其实类似状压dp。

首先答案一定是树形的,否则断开一条环上边,不影响连通性,答案不会变劣。

用f[x][y][s]表示以x,y为根的,经过了至少 s的景点的树,这里的s是压过的0/1表示的景点是否访问过的状态。

有两种状态转移,一种是合并两棵树f[x][y][s]:=f[x][y][t]+f[x][y][s xor t]-cost[x][y](其中t是s的真子集),另一种是换根f[x’][y’]:=f[x][y]+cost[x’][y’]。

其中有一个技巧是枚举真子集时一开始t:=s;每次t:=(t-1) and s;就能得到一个真子集,结束条件是t=0。

由于我是个蒟蒻,所以有两个错调了好久,一个是循环队列head<>tail写成了head< tail;还有一个是在同一层s内的搜索要拿x,y更新tx,ty才符合正常的搜索顺序,我居然写反了。。。

const
dx:array[1..4] of longint=(0,0,-1,1);
dy:array[1..4] of longint=(-1,1,0,0);
INF=maxlongint>>1;
mx=101;
type
rec=record
x,y,s:longint;
end;
var
f,cnt:array[1..10,1..10,0..1024] of longint;
hash:array[0..10,0..10,0..1024] of boolean;
map:array[1..10,1..10] of boolean;
pre:array[1..10,1..10,0..1024,0..1] of rec;
a:array[1..10,1..10] of longint;
q:array[0..1024] of longint;
vis:array[0..1024] of boolean;  n,m,e,x,y,k,head,tail,s,t,ans,ansx,ansy,i,line,tot:longint;
procedure SPFA(s:longint);
var
vis:array[1..10,1..10] of boolean;
q:array[0..mx] of rec;
head,tail,x,y,k,tx,ty:longint;
begin
try
fillchar(vis,sizeof(vis),false);
head:=1;tail:=1;tot:=0;
for x:=1 to n do
for y:=1 to m do
for k:=1 to 4 do
begin
tx:=x+dx[k];
ty:=y+dy[k];
if (tx<1)or(ty<1)or(tx>n)or(ty>m)
then continue;
if f[x][y][s]+a[tx][ty]<f[tx][ty][s] then
begin
f[tx][ty][s]:=f[x][y][s]+a[tx][ty];
cnt[tx][ty][s]:=0;
pre[tx][ty][s][0].x:=x;
pre[tx][ty][s][0].y:=y;
pre[tx][ty][s][0].s:=s;
if not vis[tx][ty] then
begin
vis[tx][ty]:=true;
q[tail].x:=tx;
q[tail].y:=ty;
inc(tail);if tail>mx then tail:=1;
end;
end;
end;
while head<>tail do
begin
x:=q[head].x;
y:=q[head].y;
inc(head);if head>mx then head:=1;
for k:=1 to 4 do
begin
tx:=x+dx[k];
ty:=y+dy[k];
if (tx<1)or(ty<1)or(tx>n)or(ty>m)
then continue;
if f[x][y][s]+a[tx][ty]<f[tx][ty][s] then
begin
f[tx][ty][s]:=f[x][y][s]+a[tx][ty];
cnt[tx][ty][s]:=0;
pre[tx][ty][s][0].x:=x;
pre[tx][ty][s][0].y:=y;
pre[tx][ty][s][0].s:=s;
if not vis[tx][ty] then
begin
vis[tx][ty]:=true;
q[tail].x:=tx;
q[tail].y:=ty;
inc(tail);if tail>mx then tail:=1;
end;
end;
end;
vis[x][y]:=false;
end;
end;
procedure dfs(x,y,s:longint);
var
i:longint;
begin
if (x=0)or(hash[x][y][s])
then exit;
map[x][y]:=true;
hash[x][y][s]:=true;
for i:=0 to cnt[x][y][s] do
dfs(pre[x][y][s][i].x,pre[x][y][s][i].y,pre[x][y][s][i].s);
end;
begin
assign(input,'trip.in');reset(input);
assign(output,'trip.out');rewrite(output);
read(n,m);e:=-1;
for x:=1 to n do
for y:=1 to m do
for k:=0 to 1<<10-1 do
f[x][y][k]:=INF;
for x:=1 to n do
for y:=1 to m do
begin
read(a[x][y]);
if a[x][y]=0 then
begin
inc(e);
f[x][y][1<<e]:=a[x][y];
end;
end;
for x:=1 to n do
for y:=1 to m do
f[x][y][0]:=a[x][y];
head:=1;tail:=2;
q[1]:=0;vis[0]:=true;
while head<tail do
begin
s:=q[head];
for x:=1 to n do
for y:=1 to m do
begin
t:=s;t:=(t - 1) and s;
while t>0 do
begin
if f[x][y][t]+f[x][y][s xor t]-a[x][y]<f[x][y][s] then
begin
f[x][y][s]:=f[x][y][t]+f[x][y][s xor t]-a[x][y];
cnt[x][y][s]:=1;
pre[x][y][s][0].x:=x;
pre[x][y][s][0].y:=y;
pre[x][y][s][0].s:=t;
pre[x][y][s][1].x:=x;
pre[x][y][s][1].y:=y;
pre[x][y][s][1].s:=s xor t;
end;
t:=(t - 1) and s;
end;
end;
SPFA(s);
for i:=0 to e do
if (s and 1 << i=0)and(not vis[s xor 1<<i]) then
begin
vis[s xor 1<<i]:=true;
q[tail]:=s xor 1 << i;
inc(tail);
end;
inc(head);
end;
ans:=maxlongint;
for x:=1 to n do
for y:=1 to m do
if f[x][y][1<<(e+1)-1]<ans then
begin
ans:=f[x][y][1<<(e+1)-1];
ansx:=x;
ansy:=y;
end;
if e>=0 then writeln(ans) else writeln(0);
if e>=0 then dfs(ansx,ansy,1<<(e+1)-1);
for x:=1 to n do
begin
for y:=1 to m do
if a[x][y]=0
then write('x')
else if map[x][y]
then write('o')
else write('_');
writeln;
end;
close(input);close(output);
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息