Wannafly挑战赛16 打怪

题目:

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

输入描述:

给出四个整数a,b,c,n (1 <= a,b,n <= 100, 1 <= c <= 20)
接下来一行给出a个数字表示xi    (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)

样例:

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求最短路。

扫描二维码关注公众号,回复: 1371111 查看本文章

注意:

先求Floyd确实,状态转换时 d[i-1][j][k] -> d[i][a][b] 不需要在对 a,b两重for循环枚举,直接先转到a再转到b就行了。

#include <iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
const int maxn = 200;
const ll inf = (1e18);
int a,b,n,c;
ll d[maxn+5][maxn+5][maxn+5];
ll x[maxn+5],y[maxn+5],f[maxn+5][maxn+5],g[maxn+5][maxn+5],h[25][maxn+5][maxn+5],w[maxn+5],t[maxn+5];
int main()
{
    scanf("%d %d %d %d",&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]);

    for(int i=1; i<=n; i++)scanf("%lld",&w[i]);
    for(int i=1; i<=n; i++)scanf("%lld",&t[i]);

    for(int k=1; k<=a; k++)
        for(int i=1; i<=a; i++)
            for(int j=1; j<=a; j++) f[i][j] = min(f[i][j],f[i][k]+f[k][j]);

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

    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]+(w[i]%h[t[i]][j][k]!=0);
    }
    //下面是错误的转换方式。
    /*for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=a; j++)
        {
            for(int k=1; k<=b; k++)
            {
                d[i][j][k] = inf;
                for(int r=1; r<=a; r++) d[i][j][k] = min(d[i][j][k],d[i-1][r][k]+f[r][j]);

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

                d[i][j][k]+=w[i]/h[t[i]][j][k] + (w[i]/h[t[i]][j][k]!=0);
            }
        }
    }
    或者这样菜鸡写法:
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=a; j++)
        {
            for(int k=1; k<=b; k++)
            {
                for(int f=1;f<=a;f++)
                {
                   for(int p=1;p<=b;p++)
                   {
                      d[i][j][k] = min(d[i][j][k],d[i-1][a][b]+g[p][k]+f[f][j]);
                   }
                }
            }
        }

    }
    */
    ll ans = inf;
    for(int i=1; i<=a; i++)
        for(int j=1; j<=b; j++) ans = min(ans,d[n][i][j]);
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_32944513/article/details/80517153
今日推荐