【搜索】【poj 2531】Network Saboteur
问题
给你一个n个节点的图,让你将该图分成两部分,使得两部分之间的边的权值和最大。
分析
一开始看以为是图论,但是算法比较高级。再看数据范围只有20,所以只需根据题意枚举一侧的节点即可。用dfs,其实就是生成组合数。注意状态表示和更新的方法,记下当前一共找到了几个点,最后一个点的位置,和当前得到的值。每次新加入一个节点,只需操作和加入的点有关的边即可。
有两个剪枝:
1.可行性:由于是组合数,只要搜到n div 2 个数即可确定全部情况。注意这句话要放在更新最值的后面。
2.最优性:如果当前加入新点之后的值比加之前得到的值大,则继续向下搜索,注意这里不能和当前的最大值比较。(why)该搜索的实质就是找一个点集,将其他点依次尝试加入点集,得到新值,那么如果当前新节点加入之后比先前未加该点的值都要小,则可用数学方法证明含该点之后搜到的状态都要比不含该点时小。
code
program liukeke;
var
map:array[0..20,0..20] of longint;
v:array[1..450] of boolean;
n,ans,i,j:longint;
procedure dfs(depth,x,now:longint);
var
i,temp,j:longint;
begin
if now>ans then ans:=now;
if depth>n div 2 then exit;
for i:=x to n do
if not v[i] then
begin
temp:=now;
for j:=1 to n do
if (not v[j]) then inc(temp,map[i,j]) else dec(temp,map[i,j]);
if temp>now then
begin
v[i]:=true;
dfs(depth+1,i+1,temp);
v[i]:=false;
end;
end;
end;
begin
readln(n);
for i:=1 to n do
begin
for j:=1 to n do
read(map[i,j]);
readln;
end;
dfs(1,1,0);
writeln(ans);
end.
反思
明确搜索的思路,用正确的状态表示,便于剪枝。
浙公网安备 33010602011771号