T1 金币(coin)
(WOJ4819)
【题目描述】
沙雕在玩一款收集类游戏,这款游戏每一关的地图可以看成一个
n
n
n 行
n
n
n 列的网格,每个格子有宝藏(
T
T
T)、起点(
S
S
S)、红色(
R
R
R)、绿色(
G
G
G)、蓝色(
B
B
B)五种可能,其中起点有且仅有一个,宝藏有且仅有
k
k
k 个。沙雕从起点出发寻宝,每一步可以向上下左右四个方向中的一个行走一步,但不能走出网格;它需要从起点出发,在关卡中收集至少
L
X
LX
LX 个、至多
R
X
RX
RX 个宝藏,收集完毕后可以立即过关(无论停留在哪个网格)。当沙雕每落在一个红色格子时,它需要付出
R
R
R 个金币;每落在一个绿色格子时,它需要付出
G
G
G个金币;每落在一个蓝色格子时,它需要付出
B
B
B 个金币;落在一个宝藏格子时,它可以收集宝藏并获得
T
T
T 个金币,然后这个宝藏格子将变成空地。
沙雕希望自己在过关的时候获得尽量多的金币(若必须付出若干金币则认为获得负数的金币),你能帮它计算出它最多获得多少金币吗?
【输入格式】
从文件coin.in 中读入数据。
第一行为五个非负整数
n
、
k
、
T
、
L
X
、
R
X
n、k、T、LX、RX
n、k、T、LX、RX。
第二行为三个非负整数
R
、
G
、
B
R、G、B
R、G、B。
接下来n 行每行为一个长度为n 的字符串,表示网格地图。
【输出格式】
输出到文件coin.out 中。
输出一行一个整数表示最多能获得的金币数。
【样例1 输入】
5 5 100 2 3
10 2 5
RGRTB
TSGGB
RRBTG
BTRBG
RBRTR
【样例1 输出】
294
【样例1 解释】
一个可行的最优解为:左右右右上下下。
【样例2】
见选手目录下的coin/coin2.in 与coin/coin2.ans。
【子任务】
对于100% 的数据满足:
1
≤
n
≤
501
,
1
≤
L
X
≤
R
X
≤
k
≤
10
,
0
≤
R
,
G
,
B
,
T
≤
1
0
5
1\le n\le 501,1\le LX\le RX \le k\le 10,0\le R,G,B,T\le 10^5
1≤n≤501,1≤LX≤RX≤k≤10,0≤R,G,B,T≤105。
思路:
以每个宝藏为起点跑最短路,求出每个宝藏到另外宝藏的最小花费。全排列宝藏,计算最大收入即可。
考试不要想复杂了!
代码:
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define re register
inline int in{
int s=0,f=1;char x;
for(x=getchar();!isdigit(x);x=getchar()) if(x=='-') f=-1;
for( ;isdigit(x);x=getchar()) s=(s<<1)+(s<<3)+(x&15);
return s*f;
}
const int A=505;
const int N=3e5+5;
const int INF=1e9;
int n,s_all,lx,rx;
int T,R,G,B;
char ch;
int mapp[A][A];
int s_x[15],s_y[15],s_k;
int star[15];
int val[N];
int head[N],tot;
struct Road{
int nex,to;
}road[8*N];
inline void ljb(int x,int y){
road[++tot].nex=head[x],road[tot].to=y,head[x]=tot;
}
int head_[100],tot_;
struct Road_{
int nex,to,w;
}road_[2000];
inline void ljb_(int x,int y,int w){
road_[++tot_].nex=head_[x],road_[tot_].to=y,road_[tot_].w=w,head_[x]=tot_;
}
inline int d(int x,int y){
return (x-1)*n+y;
}
int s[15][N];
bool ex[N];
int s_[15][15];
bool use[15];
int ans=-INF;
inline void scan(){
n=in,s_all=in,T=in,lx=in,rx=in,R=in,G=in,B=in;
for(re int i=1;i<=n;++i)
for(re int j=1;j<=n;++j){
ch=getchar();
while(ch!='T'&&ch!='S'&&ch!='R'&&ch!='G'&&ch!='B')
ch=getchar();
if(ch=='T'){
mapp[i][j]=T;
s_x[++s_k]=i,s_y[s_k]=j;
}
if(ch=='S'){
mapp[i][j]=0;
s_x[0]=i,s_y[0]=j;
}
if(ch=='R') mapp[i][j]=(-1)*R;
if(ch=='G') mapp[i][j]=(-1)*G;
if(ch=='B') mapp[i][j]=(-1)*B;
}
return;
}
inline void build(){
for(re int i=0;i<=s_all;++i)
star[i]=d(s_x[i],s_y[i]);
for(re int i=1;i<=n;++i)
for(re int j=1;j<=n;++j)
if(mapp[i][j]<0) val[d(i,j)]=(-1)*mapp[i][j];
for(re int i=1;i<=n;++i)
for(re int j=1;j<=n;++j){
if(i-1>0&&i-1<=n) ljb(d(i,j),d(i-1,j));
if(i+1>0&&i+1<=n) ljb(d(i,j),d(i+1,j));
if(j-1>0&&j-1<=n) ljb(d(i,j),d(i,j-1));
if(j+1>0&&j+1<=n) ljb(d(i,j),d(i,j+1));
}
return;
}
inline void djk(int now){
fill(s[now]+1,s[now]+d(n,n)+1,INF);
memset(ex,0,sizeof(ex));
priority_queue <pair<int,int> > q;
int be=star[now];
s[now][be]=0,ex[be]=0;
q.push(make_pair(0,be));
while(!q.empty()){
int x=q.top().second;q.pop();
if(ex[x]) continue;
ex[x]=1;
for(re int y=head[x];y;y=road[y].nex){
int z=road[y].to;
if(s[now][z]>s[now][x]+val[z]){
s[now][z]=s[now][x]+val[z];
q.push(make_pair(-s[now][z],z));
}
}
}
return;
}
inline void prepare(){
for(int i=0;i<=s_all;i++)
for(int j=0;j<=s_all;j++)
s_[i][j]=s[i][star[j]];
return;
}
inline void DFS(int now,int num,int mon){
if(num>rx) return;
if(num>=lx&&num<=rx)
ans=max(ans,mon);
if(ans+(s_all-num)*T<=ans) return;
for(int i=0;i<=s_all;i++){
if(use[i]) continue;
use[i]=1;
DFS(i,num+1,mon-s_[now][i]+T);
use[i]=0;
}
return;
}
signed main(){
scan();
build();
for(re int i=0;i<=s_all;++i)
djk(i);
prepare();
use[0]=1;
DFS(0,0,0);
printf("%d\n",ans);
return 0;
}