题目:
有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求最短路。
注意:
先求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; }