Keyboarding(信息学奥赛一本通-T1452)
【題目描述】
給定一個 r 行 c 列的在電視上的“虛擬鍵盤”,通過「上,下,左,右,選擇」共 555 個控制鍵,你可以移動電視屏幕上的光標來打印文本。一開始,光標在鍵盤的左上角,每次按方向鍵,光標總是跳到下一個在該方向上與當前位置不同的字符,若不存在則不移動。每次按選擇鍵,則將光標所在位置的字符打印出來。
現在求打印給定文本(要在結尾打印換行符)的最少按鍵次數。
【輸入】
第一行輸入 r,c。
接下來給出一個 r×c 的鍵盤,包括大寫字母,數字,橫線以及星號(星號代表 Enter 換行)。
最后一行是要打印的文本串 S,SSS 的長度不超過 10000。
【輸出】
輸出打印文本(包括結尾換行符)的最少按鍵次數。保證一定有解。
【輸入樣例】
輸入樣例1
2 19
ABCDEFGHIJKLMNOPQZY
X*****************Y
AZAZ
輸入樣例2
5 20
12233445566778899000
QQWWEERRTTYYUUIIOOPP
-AASSDDFFGGHHJJKKLL*
--ZZXXCCVVBBNNMM--**
--------------------
ACM-ICPC-WORLD-FINALS-2015
輸入樣例3
6 4
AXYB
BBBB
KLMB
OPQB
DEFB
GHI*
AB
【輸出樣例】
輸出樣例1
19
輸出樣例2
160
輸出樣例3
7
思路:
很容易想到是 BFS,但直接用 BFS 來會 TLE,因此我們需要進行優化
考慮對后置點進行優化,我們知道,通過 BFS 到達的點,如果之前被訪問過,那么肯定之前訪問的步數最小,因此在 BFS 的過程中,可以記錄打印出的字符的位置,這樣一來,如果一個后置點的位置要小于前置點,那么無論如何距離也不可能更小,這樣就不用向下進行擴展了,同時,如果后置點的位置更大,那么就將當前點的位置賦給后置點
【源程序】
#include<iostream> #include<cstdio> #include<cstdlib> #include<string> #include<cstring> #include<cmath> #include<ctime> #include<algorithm> #include<utility> #include<stack> #include<queue> #include<vector> #include<set> #include<map> #include<bitset> #define PI acos(-1.0) #define INF 0x3f3f3f3f #define LL long long #define Pair pair<int,int> LL quickPow(LL a,LL b){ LL res=1; while(b){if(b&1)res*=a; a*=a; b>>=1;} return res; } LL multMod(LL a,LL b,LL mod){ a%=mod; b%=mod; LL res=0; while(b){if(b&1)res=(res+a)%mod; a=(a<<=1)%mod; b>>=1; } return res%mod;} LL quickMultPowMod(LL a, LL b,LL mod){ LL res=1,k=a; while(b){if((b&1))res=multMod(res,k,mod)%mod; k=multMod(k,k,mod)%mod; b>>=1;} return res%mod;} LL quickPowMod(LL a,LL b,LL mod){ LL res=1; while(b){if(b&1)res=(a*res)%mod; a=(a*a)%mod; b>>=1; } return res; } LL getInv(LL a,LL mod){ return quickPowMod(a,mod-2,mod); } LL GCD(LL x,LL y){ return !y?x:GCD(y,x%y); } LL LCM(LL x,LL y){ return x/GCD(x,y)*y; } const double EPS = 1E-6; const int MOD = 1000000000+7; const int N = 50+5; const int dx[] = {-1,0,0,1,1,-1,1,1}; const int dy[] = {0,-1,1,0,-1,1,-1,1}; using namespace std;struct Node {int x, y; //橫縱坐標int op, step; //選擇次數,按鍵次數Node() {}Node(int x, int y, int op, int step) : x(x), y(y), op(op), step(step) {} }; struct Next{//下一步的坐標int x, y;Next() {}Next(int x,int y):x(x),y(y){} }nxt[N][N][4]; int n, m; char str[N][N], s[10000+5]; int G[N][N]; int vis[N][N]; void BFS(int len) {memset(vis, -1, sizeof(vis));queue<Node> Q;Q.push(Node(1, 1, 0, 0));while (!Q.empty()) {Node now = Q.front();Q.pop();int x = now.x, y = now.y;int op = now.op, step = now.step;if (str[x][y] == s[op + 1]) {Q.push(Node(x, y, op + 1, step + 1));if(op+1==len){printf("%d\n", step + 1);return;}}else{for (int i = 0; i < 4; i++) {int nx = nxt[x][y][i].x, ny = nxt[x][y][i].y;if(nx==0)continue;if(vis[nx][ny]<op){vis[nx][ny] = op;Q.push(Node(nx, ny, op, step + 1)) ;}}}} } int main() {while (scanf("%d%d", &n, &m) != EOF) {for (int i = 1; i <= n; i++)scanf("%s", str[i] + 1);scanf("%s", s + 1);int len = 1;while(s[len])len++;s[len] = '*';//預處理判斷能走的地方for (int i = 1; i <= n; i++) { //枚舉行for (int j = 1; j <= m; j++) { //枚舉列for (int k = j - 1; k >= 1; k--) { //向上if (str[i][j] != str[i][k]) {nxt[i][j][0] = Next(i, k);break;}}for (int k = j + 1; k <= m; k++) { //向下if (str[i][j] != str[i][k]) {nxt[i][j][1] = Next(i, k);break;}}for (int k = i - 1; k >= 1; k--) { //向左if (str[i][j] != str[k][j]) {nxt[i][j][2] = Next(k, j);break;}}for (int k = i + 1; k <= n; k++) { //向右if (str[i][j] != str[k][j]) {nxt[i][j][3] = Next(k, j);break;}}}}BFS(len);}return 0; }?
總結
以上是生活随笔為你收集整理的Keyboarding(信息学奥赛一本通-T1452)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 矩阵中不重复的元素(51Nod-1024
- 下一篇: 最多分成多少块(51Nod-2502)