【搜索】【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.

反思

明确搜索的思路,用正确的状态表示,便于剪枝。

posted @ 2011-05-07 17:39  liukee  阅读(355)  评论(0编辑  收藏  举报