本题数据范围很小,因此直接根据右侧爆搜左侧选择哪个,再加上一个可行性剪枝就行
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int inf=0x3f3f3f3f; const int N=1e5+10; const int mod=1e9+7; char g[20][20]; char a[20][20]; int in[N],tag[N],w[N]; vector<int> go[N]; vector<int> con[N]; int n; ll ans=1e18; void init(){ int i; memset(in,0,sizeof in); memset(tag,0,sizeof tag); for(i=0;i<=n;i++){ go[i].clear(); con[i].clear(); } } int cal(int x,int y) { if(!y) return 0; int ans=1; for(int i=1;i<=y;++i) ans=(ans*x); return ans; } void dfs(int u,ll sum){ if(u==n+1){ ans=min(ans,sum); return ; } if(sum>=ans){ return ; } for(auto x:go[u]){ if(!tag[x]){ for(auto y:con[x]){ tag[y]++; } in[x]++; dfs(u+1,sum+cal(w[x],in[x])-cal(w[x],in[x]-1)); in[x]--; for(auto y:con[x]){ tag[y]--; } } } } int main(){ ios::sync_with_stdio(false); int t; cin>>t; while(t--){ cin>>n; init(); ans=1e18; int i,j; for(i=1;i<=n;i++){ for(j=1;j<=n;j++){ cin>>g[i][j]; if(g[i][j]=='1'){ go[j].push_back(i); } } } for(i=1;i<=n;i++){ for(j=1;j<=n;j++){ cin>>a[i][j]; if(a[i][j]-'0'){ con[i].push_back(j); con[j].push_back(i); } } } for(i=1;i<=n;i++) cin>>w[i]; int sign=0; for(i=1;i<=n;i++){ if((int)go[i].size()==0){ sign=1; break; } } if(sign){ cout<<-1<<endl; } else{ dfs(1,0); if(ans==1e18){ cout<<-1<<endl; } else cout<<ans<<endl; } } return 0; }