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[l−1,x,y]+a[l],f[l−1,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.