1. 程式人生 > >ACM/ICPC 2018亞洲區預選賽北京賽站網路賽 A BFS B 暴力

ACM/ICPC 2018亞洲區預選賽北京賽站網路賽 A BFS B 暴力

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);
	} 
}