非常好的一道搜索题
首先没有别的好办法就只能搜,基于对称性我只要搜对角线上半部分即可
然后有些惯用的剪枝啦什么的,具体见程序
然后代码很短,然后TLE了(但好像也有人过了)
然后就不知道怎么优化了,看到CLJ大神的空间发现这道题是可以记忆化搜索的orz
首先当搜索完某个队伍的胜负情况后,观察剩下的队伍已确定的得分和最终得分之差,我们称作剩余状态
显然,我们对后面队伍胜负的搜索得到的方案数与之前的搜索状态无关
并且,像剩下三支队伍剩余状态是1 0 3和 0 3 1是等价的,方案数相同(即顺序并不影响)
也就是说如果两次搜索的剩余状态一样,我们直接加即可,不用再搜一次
因此我们想到了记忆化搜索,对于状态的判断自然而然想到用hash

  1 const ch:array[1..3] of longint=(3,1,0);
  2       key=200007;
  3 
  4 type link=^node;
  5      node=record
  6        num,loc:longint;
  7        next:link;
  8      end;
  9 
 10 var s,c,b:array[0..10] of longint;
 11     a:array[0..1000007,0..10] of longint;
 12     w:array[0..key] of link;
 13     ans,u,i,n,tot:longint;
 14 
 15 procedure swap(var a,b:longint);
 16   var c:longint;
 17   begin
 18     c:=a;
 19     a:=b;
 20     b:=c;
 21   end;
 22 
 23 function work(m:longint):longint;   //排序,计算hash值
 24   var i,j,p:longint;
 25   begin
 26     work:=0;
 27     for i:=1 to m-1 do
 28     begin
 29       p:=i;
 30       for j:=i+1 to m do
 31         if b[j]>b[p] then p:=j;
 32       swap(b[i],b[p]);
 33     end;
 34     for i:=1 to m do
 35       work:=(work+sqr(b[i])*sqr(i)) mod key;
 36   end;
 37 
 38 function calc(l,r:longint):longint;
 39   var k,h:longint;
 40   begin
 41     h:=0;
 42     for k:=1 to n do
 43       b[k]:=100;
 44     for k:=l to r do
 45     begin
 46       inc(h);
 47       b[h]:=c[k]-s[k];
 48     end;
 49     calc:=work(h);
 50   end;
 51 
 52 procedure add(x,y:longint);
 53   var p:link;
 54       i:longint;
 55   begin
 56     new(p);
 57     inc(tot);
 58     for i:=1 to n do
 59       a[tot,i]:=b[i];
 60     p^.loc:=tot;
 61     p^.num:=y;
 62     p^.next:=w[x];
 63     w[x]:=p;
 64   end;
 65 
 66 function find(x,y:longint):longint;
 67   var p:link;
 68       f:boolean;
 69       i:longint;
 70 
 71   begin
 72     p:=w[x];
 73     while p<>nil do
 74     begin
 75       f:=true;
 76       u:=p^.loc;
 77       for i:=1 to n do
 78         if (a[u,i]<>b[i]) then
 79         begin
 80           f:=false;
 81           break;
 82         end;
 83       if f then exit(p^.num);
 84       p:=p^.next;
 85     end;
 86     if y<>-1 then add(x,y);   //没有重复的状态则插入
 87     exit(-1);
 88   end;
 89 
 90 function dfs(t,j:longint):longint;
 91   var k,h,q:longint;
 92   begin
 93     if t=n then
 94     begin
 95       if s[n]=c[n] then exit(1);
 96       exit(0);
 97     end;
 98     if s[t]>c[t] then exit(0);   //剪枝,显然确定的得分不能大于最终得分的
 99     if s[t]+(n+1-j)*3<c[t] then exit(0);  //剪枝,如果后面全胜也不能达到最终得分剪掉
100     if j=t+1 then  
101     begin
102       h:=calc(t,n);
103       q:=find(h,-1);   //-1表示只是单纯的查询
104       if q<>-1 then exit(q);  //记忆化
105     end;
106     q:=0;
107     if j<=n then
108     begin
109       for k:=1 to 3 do
110       begin
111         s[t]:=s[t]+ch[k];
112         s[j]:=s[j]+ch[4-k];
113         if not((s[j]>c[j]) or (s[j]+(n+1-t)*3<c[j])) then q:=q+dfs(t,j+1);
114         s[t]:=s[t]-ch[k];
115         s[j]:=s[j]-ch[4-k];
116       end;
117     end
118     else if s[t]=c[t] then  //搜完一支队伍我们就判重/记录剩余状态
119     begin
120       q:=dfs(t+1,t+2);
121       h:=calc(t+1,n);
122       k:=find(h,q);
123     end;
124     exit(q);
125   end;
126 
127 begin
128   readln(n);
129   for i:=1 to n do
130     read(c[i]);
131   writeln(dfs(1,2));
132 end.
View Code

 

posted on 2014-10-26 16:58  acphile  阅读(273)  评论(0编辑  收藏  举报