多校第9题:巧妙的广搜,遇到第一个P的时候,将所有的其他P都压入队列,再搜下去就会接着P开始往下搜,搜到C结束。

附代码:

View Code
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
#define V 5010
char map[V][V];
bool vis[V][V];
int dir[4][2]={{1,0},{0,1},{0,-1},{-1,0}};
struct Node
{
    int x,y;
    long long step;
}q[V];
int r,c,cost;
long long bfs(int xx,int yy)
{
    vis[xx][yy]=1;
    int head=0,tail=0;
    q[tail].x=xx;
    q[tail].y=yy;
    q[tail++].step=0;
    while(head<tail)
    {
        xx=q[head].x;
        yy=q[head].y;
        long long ss=q[head++].step;
        for(int i=0;i<4;i++)
        {
            int xxx=xx+dir[i][0];
            int yyy=yy+dir[i][1];
            if(vis[xxx][yyy]==0 && map[xxx][yyy]!='#' && xxx>=0 && xxx<r && yyy>=0 && yyy<c)
            {
                vis[xxx][yyy]=1;
                q[tail].x=xxx;
                q[tail].y=yyy;
                if(map[xxx][yyy]=='C')
                {
                    return ss;
                }
                if(map[xxx][yyy]=='*')
                {
                    q[tail++].step=ss+cost;
                }
                if(map[xxx][yyy]=='P')
                {
                    q[tail++].step=ss;
                    for(int i=0;i<r;i++)
                    {
                        for(int j=0;j<c;j++)
                        {
                            if(map[i][j]=='P')
                            {
                                vis[i][j]=1;
                                q[tail].x=i;
                                q[tail].y=j;
                                q[tail++].step=ss;
                            }
                        }
                    }
                }
            }
        }
    }
    return -1;
}

int main()
{
    long long res;
    while(cin >> r >> c >> cost)
    {
        for(int i=0;i<r;i++)
        {
            scanf("%s",map[i]);
        }
        memset(vis,0,sizeof(vis));
        for(int i=0;i<r;i++)
        {
            for(int j=0;j<c;j++)
            {
                if(map[i][j]=='Y')
                {
                    res=bfs(i,j);
                }
            }
        }
        if(res==-1) cout <<"Damn teoy!" << endl;
        else cout << res << endl;
    }
    return 0;
}

该题还有最短路算法:
给出的地图中,Y为起点,C为终点,#点不能通过,可直接忽略。所有的P为互通的传送门,故可将所以的P看作同一个点。每个能通过的点可以向上下左右四个方向走,如果对应的方向可以通过,则连边,若要走到的点是*,则边权为通过的费用,否则边权为0。
连边后求Y到C的最短路即可。

附代码:

View Code
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <queue>
#include <algorithm>
using namespace std;
#define V 5005
#define E 200100
#define typec int
int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
const typec inf=0x7FFFFFFF;
typec cost[E],dist[V];
char map[V][V];
int num[V][V];
int n,m,C,s,t,cou;
int e,pnt[E],nxt[E],head[V],prev[V],vis[V];
struct qnode{
    int v;typec c;
    qnode(int vv=0,typec cc=0) :v(vv),c(cc){}
    bool operator<(const qnode& r) const {return c>r.c;}
};
void dijkstra(int n,const int src){
    qnode mv;
    int i,j,k,pre;
    priority_queue<qnode> que;
    vis[src]=1;dist[src]=0;
    que.push(qnode(src,0));
    for(pre=src,i=1;i<n;i++){
        for(j=head[pre];j!=-1;j=nxt[j]){
            k=pnt[j];
            if(vis[k]==0 && dist[pre]+cost[j]<dist[k]){
                dist[k] = dist[pre]+cost[j];
                que.push(qnode(pnt[j],dist[k]));
                prev[k]=pre;
            }
        }
        while(!que.empty() && vis[que.top().v]==1)
            que.pop();
        if(que.empty()) break;
        mv = que.top();que.pop();
        vis[pre=mv.v]=1;
    }
}
inline void addedge(int u,int v,typec c){
    pnt[e]=v;cost[e]=c;nxt[e]=head[u];head[u]=e++;
}
void init(){
    int i,u,v;typec c;
    e=0;
    memset(head,-1,sizeof(head));
    memset(vis,0,sizeof(vis));
    memset(prev,-1,sizeof(prev));
    for(i=0;i<=n*m+1;i++) dist[i]=inf;
    cou=1;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            num[i][j]=cou++;
        }
    }
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(map[i][j]=='Y'){
                s=num[i][j];
            }
            if(map[i][j]=='C'){
                t=num[i][j];
            }
            if(map[i][j]=='#') continue;
            else if(map[i][j]=='P'){
                cou--;
                for(int k=0;k<4;k++){
                    int ii=i+dir[k][0];
                    int jj=j+dir[k][1];
                    if(!(ii>=0 && ii<n && jj>=0 && jj<m)) continue;
                    if(map[ii][jj]=='*'){
                        addedge(0,num[ii][jj],C);
                    }
                    else if(map[ii][jj]=='C'){
                        addedge(0,num[ii][jj],0);
                    }
                    else if(map[ii][jj]=='P'){
                        addedge(0,0,0);
                    }
                }
            }
            else{
                for(int k=0;k<4;k++){
                    int ii=i+dir[k][0];
                    int jj=j+dir[k][1];
                    if(!(ii>=0 && ii<n && jj>=0 && jj<m)) continue;
                    if(map[ii][jj]=='*'){
                        addedge(num[i][j],num[ii][jj],C);
                    }
                    else if(map[ii][jj]=='C'){
                        addedge(num[i][j],num[ii][jj],0);
                    }
                    else if(map[ii][jj]=='P'){
                        addedge(num[i][j],0,0);
                    }
                }
            }
        }
    }

}
int main(){
    //freopen("in.txt","r",stdin);
    while(scanf("%d%d%d",&n,&m,&C)!=EOF){
        for(int i=0;i<n;i++){
            scanf("%s",map[i]);
        }
        init();
        dijkstra(n*m+1,s);
        if(dist[t]==inf) printf("Damn teoy!\n");
        else printf("%d\n",dist[t]);
    }
    return 0;
}

1.未加边界处理,WA了几次。
2.dijkstra(n,src),点的数量n可以比实际数量多,但至少要为实际数量。

3.src为起始点,该起始点可以为任一点,不用必须是0点。

4.堆优化的邻接表dijkstra的时间复杂度为O(E*logE)