您的位置:首页 > 产品设计 > UI/UE

[PKU 3715]Blue and Red(最小点覆盖集)

2010-05-01 21:14 417 查看
【题目大意】:

军事演习 分为红蓝方
但是有的兵是好友 不能被分在不同方
问最少删掉多少人 满足条件
输出 删掉人的序号(字典序最小)

【题目分析】:

一个天津的童鞋问我的~看了看……最开始悲剧了一下~

写写发现还可以,1A之~

比较裸的一个最小点覆盖集,konig定理证明就自己翻书吧~M67那里也有……

现在比较集中的问题在于字典序的问题。经典的方法就是试删。

因为原来就是一个二分图,所以我们就不该变原来的结构,0集合的都在左边,1集合的都在右边~

这样我们得到一个初始匹配,枚举点,删点,对于在X部的点,找匹配的Y点,然后沿着反向边找增广路,如果找不到,那么就这个点就删掉,否则不删~(P.s.找到增广路相当于找到了删除点的替代品~)

对于Y部的点,沿着正向边找增广路~然后情况同上。所以要写两个find函数~

【代码(为了省工写的是邻接矩阵~)】:

program PKU_3715;
var
g:array[0..300,0..300] of boolean;
belongs,linkx,linky:array[0..300] of longint;
v,del:array[0..300] of boolean;
n,m,i,x,ans,tt,ttt,y:longint;
function find1(x:longint):boolean;
var
i:longint;
begin
if del[x] then exit(false);
for i:=1 to n do
if g[x,i] and not v[i] and not del[i] then
begin
v[i]:=true;
if (linky[i]=0) or find1(linky[i]) then
begin
linky[i]:=x;
linkx[x]:=i;
exit(true);
end;
end;
exit(false);
end;
function find2(x:longint):boolean;
var
i:longint;
begin
if del[x] then exit(false);
for i:=1 to n do
if g[i,x] and not v[i] and not del[i] then
begin
v[i]:=true;
if (linkx[i]=0) or find2(linkx[i]) then
begin
linky[x]:=i;
linkx[i]:=x;
exit(true);
end;
end;
exit(false);
end;
begin
assign(input,'a.in');
assign(output,'a.out');
reset(input); rewrite(output);
readln(tt);
for ttt:=1 to tt do
begin
readln(n,m);
for i:=1 to n do
read(belongs[i]);
fillchar(g,sizeof(g),0);
for i:=1 to m do
begin
readln(x,y);
inc(x); inc(y);
if (belongs[x]=0) and (belongs[y]=1) then g[x,y]:=true;
if (belongs[x]=1) and (belongs[y]=0) then g[y,x]:=true;
end;
fillchar(linkx,sizeof(linkx),0);
fillchar(linky,sizeof(linky),0);
fillchar(del,sizeof(del),0);
ans:=0;
for i:=1 to n do
begin
fillchar(v,sizeof(v),0);
if find1(i) then inc(ans);
end;
write(ans);
for i:=1 to n do
if belongs[i]=0 then
begin
x:=linkx[i];
if x=0 then continue;
linky[x]:=0;
linkx[i]:=0;
del[i]:=true;
fillchar(v,sizeof(v),0);
if not find2(x) then
write(' ',i-1)
else del[i]:=false;
end
else
begin
x:=linky[i];
if x=0 then continue;
linkx[x]:=0;
linky[i]:=0;
del[i]:=true;
fillchar(v,sizeof(v),0);
if not find1(x) then
write(' ',i-1)
else del[i]:=false;
end;
writeln;
end;
close(input); close(output);
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: