题目链接
最初的时候写了个dfs的深搜,后来发现会T,于是改成了DP的做法,时间复杂度降到了O(N*M^2)是不是还是很大?不过没关系,N<=100,M<=50,于是便不会超时。
我思索了一遍,觉得还是有必要发出dfs的做法,毕竟它可以帮我理解出状态转移方程——有那么些时候dfs与dp有那么点相通之处。
DFS超时解:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef long long ll;
const int maxN=105;
int N, M, a[maxN], mp[maxN][maxN];
int dfs(int x, int no)
{
int ans=0;
if(no==N)
{
if(a[N]>=0) return mp[x][a[no]];
for(int i=1; i<=M; i++) ans=max(ans, mp[x][i]);
return ans;
}
if(a[no]<0)
{
for(int i=1; i<=M; i++)
{
ans=max(ans, mp[x][i]+dfs(i, no+1));
}
}
else
{
return mp[x][a[no]]+dfs(a[no], no+1);
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&N,&M);
for(int i=1; i<=M; i++)
{
for(int j=1; j<=M; j++)
{
scanf("%d",&mp[i][j]);
}
}
for(int i=1; i<=N; i++) scanf("%d",&a[i]);
if(N==1) { printf("0\n"); continue; }
int ans=0;
if(a[1]>0) ans=dfs(a[1], 2);
else
{
for(int i=1; i<=M; i++)
{
ans=max(ans, dfs(i, 2));
}
}
printf("%d\n", ans);
}
return 0;
}
DP正解,完整代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef long long ll;
const int maxN=105;
int N, M, a[maxN], mp[maxN][maxN], dp[maxN][maxN];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(dp, 0, sizeof(dp));
scanf("%d%d",&N,&M);
for(int i=1; i<=M; i++) for(int j=1; j<=M; j++) scanf("%d",&mp[i][j]);
for(int i=1; i<=N; i++) scanf("%d",&a[i]);
int ans=0;
for(int i=2; i<=N; i++)
{
if(a[i-1]<0 && a[i]<0)
{
for(int k=1; k<=M; k++) //目前节的取值
{
for(int j=1; j<=M; j++) //指的是前一项的取值
{
dp[i][k]=max(dp[i-1][j]+mp[j][k], dp[i][k]);
}
}
}
else if(a[i-1]<0 && a[i]>=0)
{
for(int j=1; j<=M; j++) //指的是前一项的取值
{
dp[i][a[i]]=max(dp[i][a[i]], dp[i-1][j]+mp[j][a[i]]);
}
}
else if(a[i-1]>=0 && a[i]<0)
{
for(int j=1; j<=M; j++)
{
dp[i][j]=dp[i-1][a[i-1]]+mp[a[i-1]][j];
}
}
else
{
dp[i][a[i]]=dp[i-1][a[i-1]]+mp[a[i-1]][a[i]];
}
}
for(int i=1; i<=M; i++) ans=max(ans, dp[N][i]);
printf("%d\n",ans);
}
return 0;
}