ACM/ICPC 2018亞洲區預選賽北京賽站網路賽 A BFS B 暴力
阿新 • • 發佈:2019-02-03
A
題意:從S走到T,中間有P,# , " . " ,B四種符號,P代表從這個點走不需要消耗時間, " . " 代表從這裡走消耗1單位時間,另外想要通過# ,需要去B裡面取一個氧氣瓶,自身攜帶上限是5個氧氣瓶,進入一次B就能得到一個。並且通過#需要2單位時間,問能否到達T,最短時間是多少。
思路:bfs,用dis[x][y][num]記錄到(x,y)點時擁有氧氣瓶的數為num時的步數。
Code:
#include <bits/stdc++.h>
using namespace std;
const int AX = 1e2 + 66 ;
char G[AX][AX] ;
int n , m ;
struct Node{
int x , y , num ;
Node(){}
Node( int x , int y ,int num ):x(x) , y(y) , num(num){}
}s , e ;
int dis[AX][AX][6];
int dir[4][2] = {
{ 1 , 0 },
{ 0 , 1 },
{ -1, 0 },
{ 0 , -1}
};
int bfs(){
queue<Node>Q;
Q.push(s);
dis[s.x][s.y][0] = 0 ;
while( !Q.empty() ){
Node q = Q.front(); Q.pop() ;
Node pos ;
if( q.num >= 6 ) continue;
for( int i = 0 ; i < 4 ; i++ ){
int xx = q.x + dir[i][0] ;
int yy = q.y + dir[i][1] ;
if( xx < 0 || xx >= n || yy < 0 || yy >= m ) continue;
pos.x = xx ; pos.y = yy ;
if( G[xx][yy] == '#' && q. num < 1 ) continue ;
if( G[xx][yy] == '#' ){
pos.num = q.num - 1 ;
if( ~dis[xx][yy][pos.num] && dis[xx][yy][pos.num] <= dis[q.x][q.y][q.num] + 2 ){
continue ;
}
Q.push(pos);
dis[xx][yy][pos.num] = dis[q.x][q.y][q.num] + 2 ;
}else if( G[xx][yy] == 'P' ){
pos.num = q.num ;
if( ~dis[xx][yy][pos.num] && dis[xx][yy][pos.num] <= dis[q.x][q.y][q.num] ){
continue ;
}
Q.push(pos);
dis[xx][yy][pos.num] = dis[q.x][q.y][q.num] ;
}else if( G[xx][yy] == 'B' ){
pos.num = q.num + 1 ;
if( ~dis[xx][yy][pos.num] && dis[xx][yy][pos.num] <= dis[q.x][q.y][q.num] + 1 ){
continue ;
}
Q.push(pos);
dis[xx][yy][pos.num] = dis[q.x][q.y][q.num] + 1 ;
}else if( G[xx][yy] == 'T' ){
pos.num = q.num ;
if( ~dis[xx][yy][pos.num] && dis[xx][yy][pos.num] < dis[q.x][q.y][q.num] + 1 ){
continue ;
}
Q.push(pos);
dis[xx][yy][pos.num] = dis[q.x][q.y][q.num] + 1 ;
}else{
pos.num = q.num ;
if( ~dis[xx][yy][pos.num] && dis[xx][yy][pos.num] <= dis[q.x][q.y][q.num] + 1 ){
continue ;
}
Q.push(pos);
dis[xx][yy][pos.num] = dis[q.x][q.y][q.num] + 1 ;
}
}
}
int ans = -1 ;
for( int i = 0 ; i < 6 ; i ++ ){
if( ~dis[e.x][e.y][i] ){
if( ~ans ) ans = min( dis[e.x][e.y][i] , ans ) ;
else ans = dis[e.x][e.y][i] ;
}
}
return ans ;
}
int main(){
while( ~scanf("%d%d",&n,&m) && n + m ){
memset( dis , -1 , sizeof(dis) ) ;
for( int i = 0 ; i < n ; i++ ){
scanf("%s",G[i]) ; int len = strlen(G[i]) ;
for( int j = 0 ; j < len ; j++ ){
if( G[i][j] == 'S' ){
s = Node( i , j , 0 ) ;
}
if( G[i][j] == 'T' ){
e = Node( i , j , 0 ) ;
}
}
}
printf("%d\n",bfs());
}
return 0 ;
}
B
題意:找n個串的最長公共子序列,多個答案時輸出字典序最小的。
思路:因為長度只有8,n只有10,可以暴力。
找出第一個串的所有子序列,然後得到其最小字典序,暴力找剩下的串中是否會出現即可。
Code:
#include <bits/stdc++.h>
using namespace std;
char s[12][12];
int n ;
bool check( string x ){
int len = x.size() ;
for( int i = 0 ; i < n ; i++ ){
int len_s = strlen(s[i]) ;
int f = 0 ;
for( int s_ = 0 ; s_ < len_s ; s_ ++ ){
int pos = 0 ;
if( s[i][s_] == x[pos] ) pos ++ ;
for( int j = s_ + 1 ; pos < len ; j++ ){
j %= len_s ;
if( j == s_ ) break ;
if( s[i][j] == x[pos] ){
pos ++ ;
}
}
if( pos == len ){
f = 1 ; break;
}
}
if( !f ) return false ;
}return true ;
}
int main(){
while( ~scanf("%d",&n) ){
for( int i = 0 ; i < n ; i++ ){
scanf("%s",s[i]) ;
}
int le = strlen(s[0]) ;
int lim = ( 1 << le ) ;
char res[12] ;
int f = 0 ;
for( int i = 1 ; i < lim ; i++ ){
string x = "" ;
for( int j = 0 ; j < le ; j++ ){
if( i & (1<<j) ){
x += s[0][j] ;
}
}
string tmp1 = "" , tmp2 = "" ;
for( int j = 1 ; j < x.length() ; j++ ){
tmp1 = x.substr( j , le ) + x.substr( 0 , j );
if( tmp2 == "" ) tmp2 = tmp1;
else if( tmp2 > tmp1 ) tmp2 = tmp1;
}
if(tmp2 != "" && tmp2 < x) x = tmp2;
if( check(x) ){
int len_res = strlen(res) ;
int len_X = x.size();
if( f && len_res > len_X ) continue ;
if( f && len_res < len_X ){
strcpy( res , x.c_str() ) ; continue;
}
if( !f || strcmp( res , x.c_str() ) > 0 ){
strcpy(res ,x.c_str());
f = 1 ;
}
}
}
if( !f ) printf("0\n"); else printf("%s\n",res);
}
}