http://acm.hust.edu.cn:8080/judge/contest/view.action?cid=11975#problem/D

用f【i】【j】表示i号城堡到j号城堡所需要的魔法值。

首先要用floyd算出任意两个城市之间到达所需要的最小魔法值。

然后用t【i】【j】表示i号城堡从j-1号房间到达j号房间所需要的时间。

用dp【k】【i】【j】表示当前魔法值为k到达i号城堡j号房间所需要的最短时间。

如果已经知道了dp【k】【i】【j】那么我们就可以推出dp【k】【i】【j+1】,也可以推出dp【temp】【l】【j+1】(其中l是另一个城堡,temp是当期魔法值减去i号

城堡到j号城堡所需要的魔法值。其中l!=i我们需要枚举l。

本题

#include<iostream>
#include<string.h>
#include<algorithm>
#include<stdio.h>
#define inf 0x7fffffff
using namespace std;
int dp[150][20][150];
int f[20][20];
int t[20][150];
int main()
{
   int test;
   int n,m,z;
   cin>>test;
   for(int p=1;p<=test;p++)
   {
       cin>>n>>m>>z;
       for(int i=1;i<=m;i++)
           for(int j=2;j<=n;j++)
               cin>>t[i][j];
       for(int i=1;i<=m;i++)
           for(int j=1;j<=m;j++)
               cin>>f[i][j];
       for(int k=1;k<=m;k++)
           for(int i=1;i<=m;i++)
               for(int j=1;j<=m;j++)
                   if(i!=j)
                       f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
       memset(dp,-1,sizeof(dp));
       dp[z][1][1]=0;
       for(int i=2;i<=m;i++)
       {
           int temp=z-f[1][i];
           if(temp>=0)
           {
               dp[temp][i][1]=0;
           }
       }
       for(int j=1;j<n;j++)
       {
           for(int k=0;k<=z;k++)
           {
               for(int i=1;i<=m;i++)
               if(dp[k][i][j]!=-1)
               {
                   if(dp[k][i][j+1]==-1||dp[k][i][j+1]>dp[k][i][j]+t[i][j+1])
                       dp[k][i][j+1]=dp[k][i][j]+t[i][j+1];
                   for(int l=1;l<=m;l++)
                       if(l!=i)
                       {
                           int temp=k-f[i][l];
                           if(temp>=0)
                           {
                               int ans=dp[k][i][j]+t[l][j+1];
                               if(dp[temp][l][j+1]==-1||dp[temp][l][j+1]>ans)
                                   dp[temp][l][j+1]=ans;
                           }
                       }
               }
           }
       }
       int ans=inf;
       for(int i=1;i<=m;i++)
           for(int k=0;k<=z;k++)
           if(dp[k][i][n]!=-1)
               ans=min(ans,dp[k][i][n]);
       cout<<ans<<endl;
   }
   return 0;
}

 

是属于那种知道当前状态去递推后一种状态的情况。

posted on 2012-08-23 22:46  一把刷子  阅读(325)  评论(0编辑  收藏  举报