题目链接:
题意:
给你一个n*m的矩阵,矩阵上可以分为五类点。
1.‘.’代表空地。
2.‘ULRD’代表有一束射线从此处对应的方向发出。
3.‘^<>v’代表方向转换器,(能吸收所有的射线并从对应的方向发出,你可以扭动这个转换器的出射方向,每次90degree,每次花费val[i][j],而且一旦方向确定,就不能中途改变了 )
4.‘x’代表这里有一个宝石价值是c[i][j],射线可以照到但不能穿过该地方。
5.‘#’代表墙体,射线不能穿过。
问:你最多能获得多少钱(花费的钱假设可以赊账,最后再还)?
思路:
很明显的费用流,只是该如何建图?对每类点分类讨论。
对于射线:源点->射线->(宝石||墙||转换器)。
对于转换器:由于只能转换一次方向,拆点之后,出点向四个方向->(宝石||墙||转换器)。
对于宝石:宝石->汇点。
坑点:卡常(反正我的费用流板子是T了,换个板子就过了),才给2s,难怪现场赛没人过。
代码:
int v[N][N],id[N][N],n,m;
char mp[N][N];
map<char,int>dx,dy;
int ddx[]= {
-1,1,0,0};
int ddy[]= {
0,0,1,-1};
/// ///up down right left
bool isok(int x,int y) {
return x>=1&&x<=n&&y>=1&&y<=m;
}
int cal(char c,int i) {
if(c=='^') {
if(i==0)return 0;
else if(i==1)return 2;
else if(i==2)return 1;
return 3;
}
if(c=='v') {
if(i==0)return 2;
else if(i==1)return 0;
else if(i==2)return 3;
return 1;
}
if(c=='<') {
if(i==0)return 1;
else if(i==1)return 3;
else if(i==2)return 2;
return 0;
}
if(c=='>') {
if(i==0)return 3;
else if(i==1)return 1;
else if(i==2)return 0;
return 2;
}
}
void make_edge(int x,int y) {
int u=id[x][y];
if(mp[x][y]=='x') {
ac.add_edge(u,t,1,-v[x][y]);
return ;
}
if(mp[x][y]=='#'||mp[x][y]=='.') {
return ;
}
if(mp[x][y]=='U'||mp[x][y]=='D'||mp[x][y]=='L'||mp[x][y]=='R') {
int offsetx=dx[mp[x][y]];
int offsety=dy[mp[x][y]];
ac.add_edge(s,u,1,0);
for(int i=x+offsetx,j=y+offsety; isok(i,j); i+=offsetx,j+=offsety) {
if(mp[i][j]=='x') {
ac.add_edge(u,id[i][j],1,0);
break;
} else if(mp[i][j]=='#')break;
else if(mp[i][j]=='.')continue;
else if(mp[i][j]=='U'||mp[i][j]=='D'||mp[i][j]=='L'||mp[i][j]=='R') {
continue;
} else {
ac.add_edge(u,id[i][j],1,0);
break;
}
}
return ;
}
if(mp[x][y]=='^'||mp[x][y]=='v'||mp[x][y]=='<'||mp[x][y]=='>') {
ac.add_edge(u,u+m*n,1,0);
for(int k=0; k<4; k++) {
int c=cal(mp[x][y],k);
for(int i=x+ddx[k],j=y+ddy[k]; isok(i,j); i+=ddx[k],j+=ddy[k]) {
if(mp[i][j]=='x') {
ac.add_edge(u+n*m,id[i][j],1,1ll*c*v[x][y]);
break;
} else if(mp[i][j]=='#')break;
else if(mp[i][j]=='.')continue;
else if(mp[i][j]=='U'||mp[i][j]=='D'||mp[i][j]=='L'||mp[i][j]=='R') {
continue;
} else {
ac.add_edge(u+n*m,id[i][j],1,1ll*c*v[x][y]);
break;
}
}
}
return ;
}
}
int c1,c2;
int main() {
int T;
scanf("%d",&T);
dx['R']=0,dy['R']=1;
dx['L']=0,dy['L']=-1;
dx['U']=-1,dy['U']=0;
dx['D']=1,dy['D']=0;
while(T--) {
scanf("%d%d%d%d",&n,&m,&c1,&c2);
ac.init(n*m*2);
for(int i=1; i<=n; i++)scanf("%s",mp[i]+1);
for(int i=1,x,y,z; i<=c1; i++) {
scanf("%d%d%d",&x,&y,&z);
v[x][y]=z;
}
for(int i=1,x,y,z; i<=c2; i++) {
scanf("%d%d%d",&x,&y,&z);
v[x][y]=z;
}
for(int i=1; i<=n; i++)for(int j=1; j<=m; j++)id[i][j]=(i-1)*m+j;
for(int i=1; i<=n; i++) {
for(int j=1; j<=m; j++)make_edge(i,j);
}
printf("%lld\n",-ac.Dinic());
}
}