#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define gc getchar()
#define g(c) isdigit(c)
inline int read(){
char c=0;int x=0;bool f=0;
while (!g(c)) f=c=='-',c=gc;
while (g(c)) x=x*10+c-48,c=gc;
return f?-x:x;
}
typedef long long ll;
const ll inf=1e18;//无穷
const int N=16,M=1e5+100;
ll f[N][(1<<14)+100],c[N];
ll val[N][(1<<14)+100],n,m;
ll a[N][M];bool same[N][N];
vector<ll> b[N];ll fee[N][N];
inline void ckmin(ll &a,ll b){
a=(b<a?b:a);//让 a 取到 a,b 较小值
}
int tmp[N],cnt;
int main(){
n=read();m=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
a[i][j]=read();
for(int i=1;i<=n;i++){
c[i]=read();//停靠点数量
for(int j=1;j<=c[i];j++)
b[i].push_back(read());
sort(b[i].begin(),b[i].end());
for(int j=1;j<=n;j++)
for(int k=0;k<c[i];k++)
fee[i][j]+=a[j][b[i][k]];
}
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++){
register int u=0,v=0;
same[i][j]=same[j][i]=true;
while (u<c[i]&&v<c[j]){
if (b[i][u]==b[j][v]){
same[i][j]=same[j][i]=false;
break;//不能在同一深度
}
if (b[i][u]<b[j][v]) u++;
else v++;//值小的递增
}
}
for(int S=1;S<(1<<n);S++){
memset(tmp,0,sizeof(tmp));
cnt=0;//一定要记得初始化哦
for(int i=1;i<=n;i++)
if (S&(1<<(i-1)))
tmp[++cnt]=i;
register bool flag=true;
for(int i=1;i<=cnt&&flag;i++)
for(int j=i+1;j<=cnt;j++)
if (same[tmp[i]][tmp[j]]==false){
flag=false;break;
}
if (flag){
for(int i=1;i<=cnt;i++)
for(int j=1;j<=n;j++)
val[j][S]+=fee[tmp[i]][j];
}
else{
for(int i=1;i<=n;i++)
val[i][S]=inf;
}
}
for(int S=1;S<(1<<n);S++)
f[1][S]=val[1][S];
for(int i=2;i<=n;i++)
for(int S=0;S<(1<<n);S++){
f[i][S]=f[i-1][S];//init
for(int T=S;T;T=(T-1)&S)
ckmin(f[i][S],f[i-1][T]+val[i][S^T]);
}
printf("%lld",f[n][(1<<n)-1]);
return 0;
}
仿照出题人 @一扶苏一 的代码写的,但是只有 80 分。