题意:有个人,他在某个区域待了n天,这个区域有m个地方,有w种天气情况,先给出这个人行程的每天的天气情况,然后给出 从第i个地方到第j个地方的概率,也可以自身到自身,然后给出 某个地方 是某种天气的概率,问你 这个人最优可能的行程路线也就是每天待在哪个地方,
概率DP,求出哪些路线概率最大 再在其中取最小字典序的
假设方程 dp[i][j] 代表 第i天待在j城市,状态转移
dp[i][j] = max(dp[i][j],dp[i - 1][k] * mp[k][j] * pp[j][nnum[i]]);其中mp[i][j]代表由i地方到j地方的概率,pp[j][nnum[i]]代表j这个地方天气为nnum[i]的概率,0<k<m,边界dp[0][0] = 1.00;
然后交了几把发现一直WA,方程没错 觉得是精度问题,因为每次有比较大小的过程,而且乘了2000次,肯定会有误差的,于是改用了long double,但是还是错误,最后还是没做出,后来看题解 发现可以用对数来解决,这高中书白读了....把mp[i][j] 跟pp[i][j]的 概率 取对数 log(mp[i][j]),log(pp[i][j]),这样后面的状态转移方程 乘法就可以写成加法了
dp[i][j] = max(dp[i][j],dp[i - 1][k] + mp[k][j] + pp[j][nnum[i]]);
然后又开始交,发现还是一直WA,因为 mp[i][j]是有可能为0的,意思是 第i个地方不可能到第j个地方,这里要判断一下把 ,若为0 则mp[i][j] = inf,当然 pp[i][j]也有可能为0,在这里判断为是否为0考虑精度问题,我是 判断它是否小于eps, eps 我精确到了 1e-16次都不行,最后直接改成if(mp[i][j] == 0.00)反而就过了,晕死,坑点好多的题目,
int n,m,w;
int nnum[1000 + 55];
double dp[1000 + 55][100 + 55];
double mp[100 + 55][100 + 55];
double pp[100 + 55][100 + 55];
int father[1000 + 55][100 + 55];
void init() {
memset(father,0,sizeof(father));
}
bool input() {
while(cin>>n>>m>>w) {
for(int i=1;i<=n;i++)
cin>>nnum[i];
for(int i=0;i<m;i++)
for(int j=0;j<m;j++) {
cin>>mp[i][j];
if(mp[i][j] == 0.00)
mp[i][j] = -10000000;
else mp[i][j] = log(mp[i][j]);
}
for(int i=0;i<m;i++)
for(int j=0;j<w;j++) {
cin>>pp[i][j];
if(mp[i][j] == 0.00)
mp[i][j] = -10000000;
else pp[i][j] = log(pp[i][j]);
}
return false;
}
return true;
}
void dfs(int now,int pos) {
if(now == 1) {
cout<<pos;
return ;
}
dfs(now - 1,father[now][pos]);
cout<<" "<<pos;
}
void cal() {
for(int i=0;i<1000 + 55;i++)
for(int j=0;j<100 + 55;j++)
dp[i][j] = -10000000;
dp[0][0] = (double)0.00;//边界
for(int i=1;i<n + 1;i++) {
for(int j=0;j<m;j++) {
for(int k=0;k<m;k++) {
//double aa = dp[i - 1][k] + mp[k][j] + pp[j][nnum[i]];
//double bb = dp[i][j];
//cout<<aa<<"***"<<endl;
//cout<<bb<<"***"<<endl;
if(dp[i - 1][k] + mp[k][j] + pp[j][nnum[i]] > dp[i][j]) {
dp[i][j] = dp[i - 1][k] + mp[k][j] + pp[j][nnum[i]];
father[i][j] = k;
}
}
}
}
double p = -10000000;
int s;
for(int j=0;j<m;j++) {
//cout<<dp[n][j]<<endl;
if(dp[n][j] > p) {
p = dp[n][j];
s = j;
//cout<<s<<endl;
//printf("%.10lf\n",p);
}
}
dfs(n,s);
puts("");
}
void output() {
}
int main() {
int t;
cin>>t;
while(t--) {
init();
if(input())return 0;
cal();
output();
}
return 0;
}