The 14th Jilin Provincial Collegiate Programming Contest K Forager


题目链接:

题意:

给你一个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());
    }
}

猜你喜欢

转载自blog.csdn.net/qq_43653111/article/details/109537845