Description
如图是某人设想中的N×N的密码盘,用以显示自己强大的智商以及计算能力。图中每列上面有一个0或1的值,每行左边也有一个0或1的值。密码盘中有最多N*N个按钮,每个按钮有一个数值。按钮按下去之后,你会获得按钮上的分数,然后对应行和对应列的值会改变。
例如:假设按钮(1,4)的数值为k,按下它,你获得k分,然后第一行的1会变成0,第四列的0会变成1。
你的任务是,使每列上面的值和每行左边的值一一对应相等(从左到右和从上到下),并且取得最大的积分。当然了初始积分为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!”。
题解
状态压缩DP:
f[i][j][k]=max(f[u][v][k-1]+w[k],f[i][j][k-1])
代码
var
n,m,nm,sum,l:longint;
f:array [0..512,0..512,0..1] of longint;
x,y,w:array [0..81] of longint;
function max(t,k:longint):longint;
begin
if t>k then exit(t);
exit(k);
end;
procedure init;
var
i,j,t,k:longint;
s:string;
begin
readln(n);
nm:=(1 shl n)-1;
readln(s);
t:=0;
for i:=1 to n do
t:=t+(ord(s[i])-48) shl (i-1);
readln(s);
k:=0;
for i:=1 to n do
k:=k+(ord(s[i])-48) shl (i-1);
for i:=0 to nm do
for j:=0 to nm do
f[i,j,0]:=-maxlongint div 3;
f[t,k,0]:=0;
readln(m);
for i:=1 to m do
readln(x[i],y[i],w[i]);
end;
procedure main;
var
i,j,k,v,u:longint;
begin
l:=0;
for k:=1 to m do
begin
l:=l xor 1;
for i:=0 to nm do
for j:=0 to nm do
begin
u:=i xor (1 shl (x[k]-1));
v:=j xor (1 shl (y[k]-1));
f[i,j,l]:=max(f[i,j,l xor 1],f[u,v,l xor 1]+w[k]);
end;
end;
end;
procedure print;
var
i:longint;
begin
sum:=-maxlongint div 4;
for i:=0 to nm do
sum:=max(sum,f[i,i,l]);
if sum<>-maxlongint div 4 then write(sum)
else write('I am stupid!');
end;
begin
init;
main;
print;
end.