Description
【问题描述】
如图是某人设想中的N×N的密码盘,用以显示自己强大的智商以及计算能力。图中每列上面有一个0或1的值,每行左边也有一个0或1的值。密码盘中有最多N*N个按钮,每个按钮有一个数值。按钮按下去之后,你会获得按钮上的分数,然后对应行和对应列的值会改变。
例如:假设按钮(1,4)的数值为k,按下它,你获得k分,然后第一行的1会变成0,第四列的0会变成1。
你的任务是,使每列上面的值和每行左边的值一一对应相等(从左到右和从上到下),并且取得最大的积分。当然了初始积分为0。
Input
【输入】
输入文件名为mima.in。
第一行一个正整数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
【输出】
输出文件名为mima.out
输出一行,包含一个整数,表示所能取得的最大积分。如果不能使得每列上面的值和每行左边的值一一对应相等,输出“I am stupid!”。
Sample Input
6
110111
101010
7
5 2 1
3 3 -1
1 4 2
3 5 -2
5 4 3
5 5 -3
6 5 4
Sample Output
6
Data Constraint
Hint
【注释】
样例中除图中灰色的按钮以外,全部都按下。共10个测试数据。
对于第i个测试数据,N=Max{ 3 , Min{ i , 9 }}。
分析:用状态压缩DP。设F[I,J,K]为行状态为i,列状态为j,前k个按钮的最大值。可得
f[i,j,k]=max(f[i,j,k-1],f[u,v,k-1]+w[i]) (u,v为转移前的状态)。
代码:
uses math;
var
f:Array [0..512,0..512,-1..81] of longint;
a,b,w:array [1..81] of longint;
n,i,j,k,c,x,y,u,v,ans,last:longint;
s,t:string;
begin
readln(n);
readln(s);
readln(t);
last:=1 shl n-1;
for i:=1 to n do
x:=x shl 1+ord(s[i])-48;
for i:=1 to n do
y:=y shl 1+ord(t[i])-48;
readln(c);
for i:=1 to c do
readln(a[i],b[i],w[i]);
for i:=0 to 512 do
for j:=0 to 512 do
for k:=0 to 81 do
f[i,j,k]:=-maxlongint div 2;
f[x,y,0]:=0;
for k:=1 to c do
begin
for i:=0 to last do
for j:=0 to last do
begin
u:=i xor (1 shl (n-a[k]));
v:=j xor (1 shl (n-b[k]));
f[i,j,k]:=max(f[i,j,k-1],f[u,v,k-1]+w[k]);
end;
end;
ans:=-maxlongint div 3;
for i:=0 to last do
ans:=max(f[i,i,c],ans);
if ans=-maxlongint div 3 then writeln('I am stupid!')
else writeln(ans);
end.