Les questions de Huarong Road résolvent les questions d'idée de NOIP2013!

La première fois que j'ai publié une solution de problème violette, j'étais trop excitée avant sa sortie. J'ai supprimé un Ctrl + A et un retour arrière de la solution de problème que je viens d'écrire mais pas encore publiée. (C'est donc le deuxième projet)

 

portail du titre luogu

Avant:

Quelques réflexions que vous devez avoir pour faire cette question:

1. Simplifiez votre réflexion: simulez le mouvement de la grille blanche et ne pensez jamais à simuler le mouvement des pièces d'échecs. Ce sera beaucoup plus simple, sinon ce sera misérable.

2. Conversion des idées (tout a son contraire) : La règle donnée dans le titre est que les pièces peuvent être déplacées sur la grille blanche. Conjuguons-le:

La grille blanche peut être déplacée vers la pièce d'échecs, ou la grille blanche peut être échangée avec la pièce d'échecs.

3. Il n'y a toujours qu'une seule grille blanche. (La grande vérité qui semble absurde)

4. Il est d'usage d'appeler le point de départ x et le point d'arrivée ht

Choses violentes:

La violence n'est pas difficile à réaliser, c'est-à-dire faire bouger la grille vierge, puis continuer au min min ans. Il existe de nombreuses introductions détaillées à d'autres problèmes,

Je ne les répéterai pas ici.

Obtenez des idées:

Commencez d'abord par les informations de base sur le sujet.

Comment déplacer notre pièce cible?

Réfléchissez un peu. . . . . . Bien sûr, laissez la grille vierge à côté du drapeau cible! !

Un point.

Deuxièmement, expérimentez le mouvement global de la grille blanche:

Il a été constaté que le mouvement de la grille blanche peut être grossièrement divisé en deux étapes: se déplacer vers la pièce cible indépendamment de tout, puis tourner autour de la pièce (car cela peut minimiser le nombre d'étapes)

だ か ら (Donc), l'objet de notre attention, est naturellement venu à la deuxième étape.

Il n'est pas difficile de trouver que peu importe la coordonnée de la pièce d'échecs, la grille blanche n'aura toujours que quatre situations: haut, bas, gauche et droite.

Après avoir déménagé? Trouvé: d'un coup au coup suivant, il n'y a que deux types de mouvements pour la grille blanche et les pièces:

1. La grille blanche est toujours autour des pièces, mais elle est aléatoire vers le haut, le bas, la gauche et la droite.

2. La grille blanche est échangée directement avec la position de la pièce d'échecs.

Regardez les exigences du sujet: le chemin le plus court.

Ensuite, pour le premier cas, nous pouvons utiliser BFS pour trouver la distance que la grille blanche se déplace de la dernière position à la position actuelle.

Dans le second cas, le nombre d'étapes est évidemment 1.

Un autre point.

Considérez maintenant, comment enregistrer notre statut?

Pensez à utiliser un tableau en trois dimensions ok [x] [y] [k] (coordonnées x, y + numéro d'état k) pour enregistrer. (Où k: k = 0,1,2,3, correspondant à haut, bas, gauche et droite)

Enfin, regardons la plage de données du problème: nous pouvons trouver complètement le nombre de pas (avec les pièces d'échecs au centre) de toutes les coordonnées aux coordonnées adjacentes.

! ! ! La relation est si dense, pourquoi ne pas envisager de construire une carte?

Si tous les états sont considérés comme un point, alors son droit à l'état suivant est leur nombre de pas. Et si nous effectuons SPFA sur ce graphique?

Dans cette série de dist, n'est-ce pas la distance dont nous avons besoin exactement les dist correspondant aux 4 états autour du point final ht! (Prenez min, non-sens)

Les points importants obtiennent! !

Enfin, comment numéroter ces états et exécuter SPFA? Vous ne pouvez pas construire directement une carte avec un tableau en trois dimensions!

Vous avez besoin d'une formule: ((x-1) * m + y) * 4- (4-k);

Jusqu'à présent, nous avons également saisi cette question.

 

Arrière:

1. Assurez-vous de faire attention aux opérations détaillées dans le code (en particulier lorsque le BFS est en cours d'exécution)

2. L'état correspondant à k ne doit pas être oublié, la mauvaise réponse est très grave!

 

Pleine puissance!

#include <bits / stdc ++. h> en
 utilisant l'  espace de noms std;
#define N 50
 #define N2 5005
 #define isdigit (c) ((c)> = '0' && (c) <= '9')
 #define INF (~ 0u >> 1)
 const  int orz = 0 ;

inline int read(){
    int x = 0, s = 1;
    char c = getchar();
    while(!isdigit(c)){
        if(c == '-') s = -1;
        c = getchar();
    }
    while(isdigit(c)){
        x = (x << 1) + (x << 3) + (c ^ '0');
        c = getchar();
    }
    return x * s;
}

bool ma[N][N], vis[N][N];
int fx[4] = {-1, 1, 0, 0};
int fy[4] = {0, 0, -1, 1};
int n, m, ex, ey, sx, sy, htx, hty;

inline bool judge(int x, int y){
    if(x < 1 || y < 1 || x > n || y > m)return 0;
    return ma[x][y] ;
}

inline int getnum(int x, int y, int t){
    return ((x - 1) * m + y) * 4 - (4 - t);
} 

struct data{
    int x ,y;
    int step; /*存储每个坐标的信息*/
};
/* sx,sy是否可以到达htx, hty?*/
int bfs(int dx, int dy, int sx, int sy, int htx, int hty){ 
    queue <data> q;                   /*模拟可移动格子的移动*/
    memset(vis, 0, sizeof(vis));
    q.push((data){sx, sy, 0});
    vis[sx][sy] = 1; /*从起点开始*/
    while(!q.empty()){
        data now = q.front();
        q.pop();
        int x = now.x, y = now.y, step = now.step;
        if(x == htx && y == hty){
            return now.step;   /*如果到达终点*/
        }
        for(int i = 0;i < 4; i++){
            int l = x + fx[i], r = y + fy[i];
            if(judge(l, r)){
                if(vis[l][r] || (l == dx && r == dy))continue; /*如果新点已经访问过或者等于现在的*/
                q.push((data){l, r, step + 1});
                vis[l][r] = 1;
            }
        }
    }
    return INF;        /*两个点不能互相到达*/
}

struct node{
    int u, v, w;
    int next;
} t[N2];
int f[N2];

int bian = 0;
void add(int u, int v, int w){
    t[++bian].u = u;
    t[bian].v = v;
    t[bian].w = w;
    t[bian].next = f[u];
    f[u] = bian;
    return ;
}

/*预处理, 找出所有可行状态*/

bool ok[N][N][5];
void prepare(){     
    for(int i = 1;i <= n; i++)
        for(int j = 1;j <= m; j++)
            if(ma[i][j])
                for(int k = 0;k < 4; k++)
                    if(judge(i+fx[k], j+fy[k]))
                        ok[i][j][k] = 1;
    for(int i = 1;i <= n; i++)    /*空白格子围绕棋子旋转时*/
        for(int j = 1;j <= m; j++)
            for(int k = 0;k < 4; k++)
                for(int l = k + 1; l < 4; l++)  /*枚举不同的方向*/
                    if(ok[i][j][k] && ok[i][j][l]){
                        int a = getnum(i, j, k), b = getnum(i, j, l);
                        int c = bfs(i, j, i + fx[k], j + fy[k], i + fx[l], j + fy[l]);
                        if(c != INF){     /*状态之间是否可达*/
                            add(a, b, c);
                            add(b, a, c);
                        } 
                    }
    for(int i = 1;i <= n; i++)  /*空白格子和棋子交换位置*/ 
        for(int j = 1;j <= m; j++){
            if(ok[i][j][3] && ok[i][j+1][2]){
                int a = getnum(i, j, 3);     /*几种小情况*/
                int b = getnum(i, j+1, 2);
                add(a, b, 1);
                add(b, a, 1); 
            }
        }
    for(int i = 1;i <= n; i++)
        for(int j = 1;j <= m; j++){
            if(ok[i][j][1] && ok[i+1][j][0]){
                int a = getnum(i, j, 1);
                int b = getnum(i+1, j, 0);
                add(a, b, 1);
                add(b, a, 1);
            }
        }
    return ;
} 

/*进行最短路求解*/ 

queue <int> q;
bool viss[N2];
int d[N2];

int spfa(){
    memset(d, 127, sizeof(d));
    memset(viss, 0, sizeof(viss));
    int flag = d[2333]; /*之后判断用的*/
    for(int i = 0;i < 4; i++){   /*先对起点进行选取*/
        int l = sx + fx[i], r = sy + fy[i];
        if(judge(l, r)){
            int temp = bfs(sx, sy, ex, ey, l, r); /*ex,ey 是否可以到达 l,r? */
            if(temp != INF){
                int snum = getnum(sx, sy, i);
                viss[snum] = 1;
                q.push(snum);
                d[snum] = temp;
            }
        }
    }
    while(!q.empty()){   /*求所有状态间的最短路*/
        int now = q.front(); q.pop();
        viss[now] = 0;
        for(int i = f[now]; i;i = t[i].next){
            int u = t[i].u, v = t[i].v, w = t[i].w;
            if(d[v] > d[u] + w){
                d[v] = d[u] + w;
                if(!viss[v]){
                    viss[v] = 1;
                    q.push(v); 
                } 
            }
        }
    }
    int ans = INF;
    for(int i = 0; i < 4; i++){
        int num = getnum(htx, hty, i);
        ans = min(ans, d[num]);
    }
    return ans == flag ? -1 : ans;
}

int main(){
//    freopen("hh.txt", "r", stdin);
    n = read(), m = read();
    int T = read();
    for(int i = 1;i <= n; i++)
        for(int j = 1;j <= m; j++)
            ma[i][j] = read();
    prepare();
    while(T--){  /*e: 空白  s: 起点  ht:  终点*/
        ex = read(), ey = read(), sx = read(), sy = read(), htx = read(), hty = read();
        if(sx == htx && sy == hty){  /*特判*/
            puts("0");
            continue;
        }
        if(!ma[htx][hty] || !ma[sx][sy]){ /*如果起点终点根本不在图内*/
            puts("-1");
            continue;
        }
        printf("%d\n", spfa());
    }
    return orz; /*向大佬势力低头 同时拜一下CCf求AC*/
}

 

(二稿真累)

 

Je suppose que tu aimes

Origine www.cnblogs.com/wondering-world/p/12723169.html
conseillé
Classement