您的位置:首页 > 其它

pku1815 割边

2010-05-29 14:35 120 查看
这题wa了N次,就是改某个图不改某个图的问题。。

题目大意:

一群人,1表示两个人能联系0表示两个人不能联系,一个起点s一个终点t,问最少删除多少个点能使s到t收不到信息,并且让你给出一组解,要求字典序最小。

简略题解:

显然就是最大流。

把每个点拆成两个点i,i',从i向i'连一条容量为1的边,如果i和j能联系,那么从i'向j连一条容量为无穷的边。从s向s'连一条容量为无穷的边,从t向t'连一条容量为无穷的边。那么求这个网络的最大流就是第一问。

那么如何给出一组解呢,直接dfs是不行的,因为要求字典序了。我用了一个比较shax的办法就是按字典序枚举,然后删点,看最大流是否减小,若减小了那么就记录一下并且把这个点真正删掉。。这样会很慢,然后纠结的跑了500+ms。

其实还可以用dfs会很快,就是每删掉一个点,就从t到s开始dfs一条路径,这条路径包含i’--->i,如果到了说明有解。。我是后来才搜到这种方法的,所以没改。。

附程序:

program pku_1815;
const inf=10000000;
var a:array[0..201,0..201] of longint;
c,tc,av:array[0..401,0..401] of longint;
d,num:array[0..401] of longint;
n,st,ed,ans,now:longint;
{------------------------}
procedure init;
var i,j:longint;
begin
readln(n,st,ed);
for i:=1 to n do
for j:=1 to n do
read(a[i,j]);
if a[st,ed]=1 then
begin
writeln('NO ANSWER!');
halt;
end;
end;
{------------------------}
function min(x,y:longint):longint;
begin
if x<y then exit(x)
else exit(y);
end;
{------------------------}
function dfs(u,flow:longint):longint;
var i,tmp:longint;
begin
if u=ed+n then exit(flow);
dfs:=0;
for i:=1 to n*2 do
if (c[u,i]>0) and (d[u]=d[i]+1) then
begin
tmp:=dfs(i,min(flow-dfs,c[u,i]));
dec(c[u,i],tmp);
inc(c[i,u],tmp);
inc(dfs,tmp);
if dfs=flow then exit(dfs);
end;
if d[st]>=n*2 then exit;
dec(num[d[u]]);
if num[d[u]]=0 then d[st]:=n*2;
inc(d[u]);
inc(num[d[u]]);
end;
{------------------------}
procedure maxflow;
var flow:longint;
begin
ans:=0;
fillchar(d,sizeof(d),0);
fillchar(num,sizeof(num),0);
num[0]:=n*2;
while d[st]<n*2 do begin
flow:=dfs(st,maxlongint);
inc(ans,flow);
end;
end;
{------------------------}
function check(x:longint):boolean;
begin
if c[x,x+n]=1 then exit(false);
if (x=st) or (x=ed) then exit(false);
tc:=c;
c:=av;
c[x,x+n]:=0;
maxflow;
if now>ans then begin
now:=ans;
av[x,x+n]:=0;
exit(true);
end else begin
c:=tc;
exit(false);
end;
end;
{------------------------}
procedure main;
var i,j:longint;
begin
for i:=1 to n do
c[i,i+n]:=1;
c[st,st+n]:=inf;
c[ed,ed+n]:=inf;
for i:=1 to n do
for j:=1 to n do
if i<>j then
if a[i,j]=1 then c[i+n,j]:=inf;
av:=c;
tc:=c;
maxflow;
writeln(ans);
j:=ans;
now:=ans;
for i:=1 to n do
begin
if j=0 then break;
if check(i) then
begin
dec(j);
write(i,' ');
end;
end;
writeln;
end;
{------------------------}
begin
init;
main;
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: