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!”。
题解
f[k][i][j]=max(f[k−1][u][v]+w[k],f[k−1][i][j])
然后第一维可以滚
看到n<=9就要想到状压了,I am stupid那个点也是恶意满满,无力吐槽
Code
#include <stdio.h>
using namespace std;
int x[82],y[82],w[82];
int f[2][513][513];
bool p[513];
char s[255];
int max(int x,int y)
{
return x>y?x:y;
}
int main()
{
int n,m,a=0,b=0;
scanf("%d",&n);
scanf("%s",&s);
int limit=(1<<n)-1;
for (int i=1;i<=n;i++)
a+=((int)(s[i-1])-48)<<(i-1);
scanf("%s",&s);
for (int i=1;i<=n;i++)
b+=((int)(s[i-1])-48)<<(i-1);
for (int i=0;i<=limit;i++)
for (int j=0;j<=limit;j++)
f[0][i][j]=-2147483647/2;
f[0][a][b]=0;
int l=0;
scanf("%d",&m);
for (int i=1;i<=m;i++)
scanf("%d%d%d",&x[i],&y[i],&w[i]);
for (int k=1;k<=m;k++)
{
l=l^1;
for (int i=0;i<=limit;i++)
for (int j=0;j<=limit;j++)
{
int u=i^(1<<(x[k]-1));
int v=j^(1<<(y[k]-1));
f[l][i][j]=max(f[l^1][i][j],f[l^1][u][v]+w[k]);
}
}
int ans=-2147483647/3;
for (int i=0;i<=limit;i++)
if (f[l][i][i]>ans)
ans=f[l][i][i];
if (ans!=-2147483647/3)
printf("%d\n",ans);
else
printf("I am stupid!\n");
return 0;
}