用一个二进制记录当前状态。
二进制中的0代表当前点已经被走过,1代表当前点还未走过。
如果当前二进制之前计算过,且值大于当前值的话,那么就终止不走。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
int shuyu[5001];
int n;
int w[101][101];
int e[101][101];
int s[101];
int dp[5001];
void init()
{
int ns=1;
for(int i=1;i<=12;i++)
{
shuyu[ns]=i;
ns=ns*2;
}
for(int i=1;i<=5000;i++)if(shuyu[i]==0)shuyu[i]=shuyu[i-1];
}
void dos(int num,int exp,int as)
{
//cout<<num<<" "<<exp<<" "<<as<<endl;
if(num<dp[as])return ;
dp[as]=num;
if(as==0)return;
int st;
st=as;
int ed;
ed=as;
while(ed)
{
st=ed&(ed-1);
st=ed-st;
int pp=shuyu[st];
if(exp>s[pp])dos(num+w[1][pp],exp+e[1][pp],as-(1<<(pp-1)));
else dos(num,exp+e[1][pp],as-(1<<(pp-1)));
ed=ed-st;
}
}
int main()
{
int _,i,j;
init();
scanf("%d",&_);
while(_--)
{
memset(dp,0,sizeof(dp));
scanf("%d",&n);
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
scanf("%d",&e[i][j]);
}
}
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
scanf("%d",&w[i][j]);
}
}
for(i=1;i<=n;i++)
{
scanf("%d",&s[i]);
}
int as=0;
int ns=1;
for(i=1;i<=n;i++)
{
as+=(1<<(i-1));
}
as-=1;
int leap=1;
int ans=0;
while(leap)
{
leap=0;
for(i=2;i<=n;i++)
{
if(s[1]<=s[i])continue;
if((1<<(i-1))&as)
{
s[1]+=e[1][i];
as-=(1<<(i-1));
ans+=w[1][i];
leap=1;
}
}
}
if(as==0)cout<<ans<<endl;
else
{
dp[as]=ans;
dos(ans,s[1],as);
cout<<dp[0]<<endl;
}
}
}