Wannafly挑战赛16-D: 打怪(DP)

链接:https://www.nowcoder.com/acm/contest/113/D
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

有a种武器,b种属性,和c种怪物。对于第k种怪物,给出武器i和属性j的搭配在一个单位时间内对其造成的伤害h k, i,j。已知一开始使用武器i,需要时间x i,使用属性i,需要时间y i。然后从武器i直接切换成武器j,需要时间f i,j,从属性i直接切换成属性j需要时间g i,j。有一个长度为n的怪物序列,给出怪物i的血量w i和种类t i,在打怪物的时候可以随意切换武器和属性,问按顺序打死所有怪物(使得血量<=0)至少需要多少时间。

输入描述:

给出四个整数a,b,c,n (1 <= a,b,n <= 100, 1 <= c <= 20)
接下来一行给出a个数字表示x   (1 <= xi <= 1e5)
接下来一行给出b个数字表示yi    (1 <= yi <= 1e5)
接下来a行每行a个整数,表示fi,j    (fi,i = 0, 当i!=j时,1 <= fi,j <= 1e3)
接下来b行每行b个整数,表示gi,j  (gi,i = 0, 当i!=j时,1 <= gi,j <= 1e3)
接下来c个矩阵,每个矩阵有a行,每行b个整数,表示hk,i,j (1 <= hk,i,j <= 1e4)
接下来一行读入n个整数表示wi (1 <= wi <= 1e8)
接下来一行读入n个整数表示ti (1 <= ti <= c)

输出描述:

输出一个整数表示答案。
示例1

输入

复制
2 2 1 1
1 100
1 100
0 10
5 0
0 7
6 0
2 3
4 5
1001
1

输出

复制
220

题解:设状态为d[i][j][k],表示处理完第i只怪,武器是j,属性是k的最短时间。武器/属性的切换只需在打每只怪之前考虑。转移的时候,分别考虑武器,属性的转换即可。 由于武器/属性的转换是一个有向图,间接切换可能比直接切换更优,所以一开始要跑Floyd求最短路。

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+10;
const int MOD=1e9+7;
const double PI=acos(-1.0);
typedef long long ll;
ll x[200],y[200];
ll f[200][200],g[200][200];
ll h[30][200][200];
ll w[200],t[200];
ll d[101][101][101];
void Floyd(ll p[][200],int n)
{
    for(int k=1;k<=n;k++)
    {
        for(int j=1;j<=n;j++)
        {
            for(int i=1;i<=n;i++)p[i][j]=min(p[i][j],p[i][k]+p[k][j]);
        }
    }
}
int main()
{
    int a,b,c,n;
    cin>>a>>b>>c>>n;
    for(int i=1;i<=a;i++)scanf("%lld",&x[i]);
    for(int i=1;i<=b;i++)scanf("%lld",&y[i]);

    for(int i=1;i<=a;i++)
    for(int j=1;j<=a;j++)scanf("%lld",&f[i][j]);

    for(int i=1;i<=b;i++)
    for(int j=1;j<=b;j++)scanf("%lld",&g[i][j]);

    for(int i=1;i<=c;i++)
    for(int j=1;j<=a;j++)
    for(int k=1;k<=b;k++)scanf("%lld",&h[i][j][k]);

    Floyd(f,a);
    Floyd(g,b);
    for(int i=1;i<=n;i++)scanf("%lld",&w[i]);
    for(int i=1;i<=n;i++)scanf("%lld",&t[i]);
    memset(d,63,sizeof d);

    for(int i=1;i<=a;i++)
    for(int j=1;j<=b;j++)d[0][i][j]=x[i]+y[j];

    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=a;j++)
        for(int k=1;k<=b;k++)
        for(int p=1;p<=a;p++)d[i][j][k]=min(d[i][j][k],d[i-1][p][k]+f[p][j]);

        for(int j=1;j<=a;j++)
        for(int k=1;k<=b;k++)
        for(int p=1;p<=b;p++)d[i][j][k]=min(d[i][j][k],d[i][j][p]+g[p][k]);

        for(int j=1;j<=a;j++)
        for(int k=1;k<=b;k++)d[i][j][k]+=(w[i]+h[t[i]][j][k]-1)/h[t[i]][j][k];
    }
    ll ans=6e18;
    for(int i=1;i<=a;i++)
    for(int j=1;j<=b;j++)ans=min(ans,d[n][i][j]);
    cout<<ans<<endl;
    return 0;
}


猜你喜欢

转载自blog.csdn.net/mitsuha_/article/details/80458203
今日推荐