///
题意:字典中总共有w个单词.b次询问.每次给出一个4*4的字符矩阵.
可以从矩阵中任意一个位置开始.往相邻8个方向走.最后组成一个单词.
若组成的单词在字典中,则按其长度来计算分数.
长度3,4积分为1.长度5积分2.长度6积分3.长度7积分5.长度8积分11.
字典中的单词长度最多为8.矩阵中的同一个位置在一个单词中只能出现一次.可以被多个单词使用.
w<=3e5.b<=30.字典中一个单词只算一次分数.问最多能得到多少积分?
暴力dfs计算出矩阵能组成的所有单词.并用map标记即可.
字典中的单词长度最多为8 所以复杂度在O(8^8 *30).实际比较快 暴力水过.
正解:
因为dfs搜索时很多单词明显不在字典中.
可以先用Trie存字典单词.dfs暴力时若当前t不是任意一个单词前缀直接返回即可.复杂度为O(3e5*8*30)
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> ii;
const int N=2e2+5,M=4e6+5;
int T;
bool vis[N][N];
int dx[]={-1,-1,1,1};
int dy[]={-1,1,-1,1};
ii pre[N][N];
void bfs(int sx,int sy,int ex,int ey){
queue<ii> q;
q.push(ii(sx,sy));
// cout<<sx<<' '<<sy<<' ';
memset(vis,0,sizeof(vis));
vis[sx][sy]=true;
pre[sx][sy]=ii(0,0);
while(!q.empty()){
int x=q.front().first,y=q.front().second;
q.pop();
for(int i=0;i<4;i++){
for(int j=1;j<=8;j++){
int nx=x+dx[i]*j,ny=y+dy[i]*j;
if(nx>=1&&nx<=8&&ny>=1&&ny<=8&&!vis[nx][ny]){
vis[nx][ny]=true;
pre[nx][ny]=ii(x,y);
q.push(ii(nx,ny));
}
}
}
}
if(!vis[ex][ey]) cout<<"Impossible"<<'\n';
else{
stack<ii> stk;
ii now=ii(ex,ey);
while(now.first!=0){
stk.push(now);
ii tmp=pre[now.first][now.second];
now=tmp;
}
printf("%d",stk.size()-1);
while(!stk.empty()){
int x=stk.top().first,y=stk.top().second;
stk.pop();
printf(" %c %d",'A'+x-1,y);
}
printf("\n");
}
}
int main(){
cin>>T;
while(T--){
char a[20],b[20];
int sy,ey;
scanf("%s%d%s%d",a,&sy,b,&ey);
int sx=a[0]-'A'+1;
int ex=b[0]-'A'+1;
bfs(sx,sy,ex,ey);
}
return 0;
}
正解:
// @EXPECTED_RESULTS@: CORRECT
#include <iostream>
#include <vector>
#include <set>
#include <string>
#include <algorithm>
#include <assert.h>
using namespace std;
int numWords, numBoggles;
vector<string> dictionary;
string boggle[4];
bool vis[4][4];
vector<string> found;
int dx[] = { 0, 0,-1,-1,-1,+1,+1,+1};
int dy[] = {-1,+1,-1, 0,+1,-1, 0,+1};
int toScore[] = {0, 0, 0, 1, 1, 2, 3, 5, 11, 11, 11, 11, 11, 11, 11, 11, 11};
struct trie {
bool valid;
int edges[26];
int last;
};
#define MAX_TRIE (5+8*300000)
trie tries[MAX_TRIE];
int edgeCnt;
int kase;
int init() {
int id = edgeCnt;
tries[id].valid = false;
for (int i = 0; i < 26; i++) tries[id].edges[i] = -1;
edgeCnt++;
assert(edgeCnt < MAX_TRIE);
return id;
}
void add(int id, string &w, int idx) {
if (idx >= (signed) w.size()) {
tries[id].valid = true;
return;
}
int letter = (int) (w[idx] - 'A');
if (tries[id].edges[letter] == -1) {
tries[id].edges[letter] = init();
}
add(tries[id].edges[letter], w, idx + 1);
}
void rec(int i, int j, string cur, int id) {
if (i < 0 || j < 0 || i >= 4 || j >= 4) return;
if (vis[i][j]) return;
if (cur.size() >= 8) return;
vis[i][j] = true;
cur = cur + boggle[i][j];
int letter = (int) (boggle[i][j] - 'A');
int next = tries[id].edges[letter];
if (next == -1) {
vis[i][j] = false;
return;
}
if (tries[next].valid && tries[next].last < kase) {
tries[next].last = kase;
found.push_back(cur);
// cerr << "found " << cur << endl;
}
for (int c = 0; c < 8; c++) {
rec(i + dx[c], j + dy[c], cur, next);
}
vis[i][j] = false;
}
int main() {
edgeCnt = 0;
int root = init();
cin >> numWords;
for (int i = 0; i < numWords; i++) {
string t;
cin >> t;
add(root, t, 0);
}
cin >> numBoggles;
for (int i = 0; i < numBoggles; i++) {
kase = i + 1;
for (int j = 0; j < 4; j++) cin >> boggle[j];
found.clear();
for (int j = 0; j < 4; j++) {
for (int k = 0; k < 4; k++) {
rec(j,k, "", root);
}
}
string best = *(found.begin());
int score = 0;
for (vector<string>::iterator iter = found.begin(); iter != found.end(); iter++) {
if (best.size() < iter->size() || (best.size() == iter->size() && *iter < best)) {
best = *iter;
}
score += toScore[iter->size()];
}
cout << score << " " << best << " " << found.size() << endl;
}
return 0;
}