密码盘 纪中 3067 状压dp

来源:互联网 发布:深圳信科网络 编辑:程序博客网 时间:2024/06/13 23:18

Description

如图是某人设想中的N×N的密码盘,用以显示自己强大的智商以及计算能力。图中每列上面有一个0或1的值,每行左边也有一个0或1的值。密码盘中有最多N*N个按钮,每个按钮有一个数值。按钮按下去之后,你会获得按钮上的分数,然后对应行和对应列的值会改变。

你的任务是,使每列上面的值和每行左边的值一一对应相等(从左到右和从上到下),并且取得最大的积分。当然了初始积分为0。

Input

第一行一个正整数N,表示密码盘的大小。N最大为9。
第二行一个01串,表示从上到下每行左边的N个值。
第三行一个01串,表示从左到右每列上边的N个值。
下一行一个正整数k,表示按钮的数量。1≤k≤N*N。
接下来k行,每行三个整数a、b、c,表示第a行第b列处有一个数值为c的按钮。左上角的格子为第一行第一列。1≤a≤N,1≤b≤N,-100≤C≤100。不会有同一个地方出现两个按钮。

Output

输出一行,包含一个整数,表示所能取得的最大积分。如果不能使得每列上面的值和每行左边的值一一对应相等,输出“I am stupid!”。

分析

谢谢olahiuj的提示这是一个状压dp,可以把从上到下每行左边的N个值和从左到右每列上边的N个值分别当做一个二进制数,表示状态。

f[l,i,j]=max(f[l1,x,y]+a[l],f[l1,i,j])

i,j表示状态.x,y表示利用按钮l可以从状态x,y变成i,j.a[l]表示按钮l的值.输出时在f[k,i,i]中找到最大的ps:可以用滚动数组来滚动l.

代码

const  maxn=1048;type  arr=record    x,y,w:longint;end;var  f:array[0..maxn,0..maxn,0..1] of longint;  push:array[0..100] of arr;  n,m,nm:longint;  x,y:longint;procedure init;var  i,j,k:longint;  c:char;begin  readln(n);  nm:=0;  for i:=1 to n do    begin      read(c);      x:=x*2+ord(c)-48;      nm:=nm*2+1;    end;  readln;  for i:=1 to n do    begin      read(c);      y:=y*2+ord(c)-48;    end;  readln;  readln(m);  for i:=1 to m do    with push[i] do      readln(x,y,w);  for i:=0 to nm do    for j:=0 to nm do      f[i,j,1]:=-maxlongint;  f[x,y,1]:=0;end;function max(x,y:longint):longint;begin  if x>y then exit(x)         else exit(y);end;procedure main;var  i,j,k,l:longint;  x1,y1:longint;  ans:longint;begin  l:=1;  for k:=1 to m do    begin      for i:=0 to nm do        for j:=0 to nm do          begin            x1:=i xor (1 shl (n-push[k].y));            y1:=j xor (1 shl (n-push[k].x));            if f[x1,y1,l]<>-maxlongint              then f[i,j,l xor 1]:=max(f[x1,y1,l]+push[k].w,f[i,j,l])              else f[i,j,l xor 1]:=f[i,j,l];          end;      l:=l xor 1;    end;  ans:=-maxlongint;  for i:=1 to nm do    for j:=i to i do      if f[i,j,l]>ans then ans:=f[i,j,l];  if ans<>-maxlongint    then write(ans)    else write('ChuTiren is stupid!!!');end;begin  init;  main;end.
2 0
原创粉丝点击