https://nanti.jisuanke.com/t/42392
注意到n=18,于是可以快乐2^n*n*n dp
一开始用dfs去给同时消除第i个和第j个的所有合法状态加入他的vector中,然后遍历所有状态枚举vector转移,dfs常数太大超时了
2s都跑不过
然后用个2进制mask来记录一下哪些是冲突的,然后在转移的时候&一下看能不能转,就322ms过了
然后又是经典num[i][j]=0没有初始化,找一年错
艹,每次队友交题我都提醒long long 初始化,边界,自己训练的时候交之前总是忘记检查,还是没有养成好习惯= =
#include<bits/stdc++.h>
using namespace std;
int n,m,k,ans,tot;
struct node
{
int x,y;
}c[20];
int dp[1<<18],val[1<<18],s[20];
int num[8][8];
int g[20][20][2];
char ch[8][8][10];
inline void prework()
{
scanf("%d%d%d",&n,&m,&k);
tot=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%s",ch[i][j]+1);
if(ch[i][j][1]!='-')
{
num[i][j]=++tot;
c[tot]=node{i,j};
}
else
num[i][j]=0;
}
for(int i=0;i<=k;i++)
scanf("%d",&s[i]);
int mask,miy,mxy,cnt,ss;
for(int i=1;i<=tot;i++)
for(int j=i+1;j<=tot;j++)
{
cnt=0;g[i][j][0]=g[i][j][1]=0;
for(int l=1;l<=k;l++)
if(ch[c[i].x][c[i].y][l]==ch[c[j].x][c[j].y][l])
cnt++;
mask=(1<<(i-1))+(1<<(j-1));
val[mask]=s[cnt];
miy=min(c[i].y,c[j].y);mxy=max(c[i].y,c[j].y);
ss=0;
for(int k=miy;k<=mxy;k++)
if(num[c[i].x][k])
ss|=1<<(num[c[i].x][k]-1);
for(int k=c[i].x;k<=c[j].x;k++)
if(num[k][c[j].y])
ss|=1<<(num[k][c[j].y]-1);
g[i][j][0]=ss;
ss=0;
for(int k=c[i].x;k<=c[j].x;k++)
if(num[k][c[i].y])
ss|=1<<(num[k][c[i].y]-1);
for(int k=miy;k<=mxy;k++)
if(num[c[j].x][k])
ss|=1<<(num[c[j].x][k]-1);
g[i][j][1]=ss;
}
}
inline void mainwork()
{
for(register int i=0;i<(1<<tot);++i)
dp[i]=-1;
dp[(1<<tot)-1]=0;int mask;
for(register int ss=(1<<tot)-1;ss>=0;--ss)
{
if(dp[ss]==-1)
continue;
for(register int i=0;i<tot;++i)
if(ss>>i&1)
for(register int j=i+1;j<tot;++j)
if(ss>>j&1)
{
mask=(1<<i)+(1<<j);
if((g[i+1][j+1][0]&ss)==mask || (ss&g[i+1][j+1][1])==mask)
{
dp[ss^mask]=max(dp[ss^mask],dp[ss]+val[mask]);
}
}
}
}
inline void print()
{
printf("%d\n",dp[0]);
}
int main()
{
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
prework();
mainwork();
print();
}
return 0;
}