https://www.acmicpc.net/problem/9997

 

9997번: 폰트

첫째 줄에 단어의 개수 N (1 ≤ N ≤ 25)가 주어진다. 다음 N개 줄에는 사전에 포함되어있는 단어가 주어진다. 단어의 길이는 100을 넘지 않으며, 중복되는 단어는 주어지지 않는다.

www.acmicpc.net

 

 

 

[난이도] Gold2
[유형] 비트마스크

[풀이]
주어지는 단어에 포함된 알파벳을 26자리 비트 int로 변환이 가능합니다.
int로 변환을 해준 뒤에 재귀를 이용해서 만들 수 있는 경우의 수를 모두 조합해주면 됩니다.
현재 단어를 포함 시킬때는 비트or 연산을 이용해 O(1)에 연산이 가능합니다.

 

#include <iostream>
#include <string>
using namespace std;
int N,ans,a[25];
void sol(int n,int b){
    if(n==N) {
        if(b==(1<<26)-1) ans++;
        return;
    }
    sol(n+1,b);
    sol(n+1,b|a[n]);
}
int main(){
    cin >> N;
    for(int i=0;i<N;i++) {
        string s;
        cin >> s;
        int b=0;
        for(auto c : s) b |= (1<<(c-'a'));
        a[i]=b;
    }
    sol(0,0);
    cout << ans;
}


https://github.com/has2/Problem-Solving/blob/master/boj-solved.ac/Gold2/9997.cpp

https://programmers.co.kr/learn/courses/30/lessons/81304

 

코딩테스트 연습 - 미로 탈출

4 1 4 [[1, 2, 1], [3, 2, 1], [2, 4, 1]] [2, 3] 4

programmers.co.kr

 

 

[난이도] level4
[유형] 비트마스크

[풀이]
트랩에는 연결된 간선이 역방향인 경우와 정방향인 경우 두가지 상태가 있습니다.
간선이 역방향이려면 트랩에 홀수번 방문한 상태여야 하며, 정방향인 경우는 방문을 안했거나
짝수번 방문한 상태입니다.

트랩의 개수가 최대 10개밖에 되지 않으므로 10개의 비트로 아래와 같이 트랩의 상태를 저장할 수 있습니다.
0000000000(0)~1111111111(2^10-1) (0인 경우 정방향, 1인 경우 역방향)

이를 이용해 vector<pair<int,int>> adj[1025][1001] 형태의 adj[state][node] 2차원 인접리스트를 선언한 뒤
state에 따라 올바른 간선 방향을 가지는 인접 리스트를 각각 만들어줍니다.

트랩의 개수가 k개라면 인접 리스트는 총 2^k개가 나올 수 있습니다.
만약 어떤 노드 u,v를 연결하는 간선이 입력으로 주어질 때,
i)   u,v가 모두 정방향인 경우(둘다 트랩이 아니거나, 트랩이어도 state 비트마스크에서 두 트랩 모두 0)
      u,v는 u->v 방향 그대로 저장

ii)  u,v 둘중 하나가 트랩이면서 역방향인 경우
      간선을 뒤집어야 하므로 v->u 방향으로 저장

iii) u,v 모두 트랩이면서 역방향인 경우
      이 경우에는 간선이 u에 의해 한번 뒤집히고, v에 의해 또한번 뒤집히므로 결국 정방향인 상태가 됩니다.
      그대로 u->v 방향으로 저장

위와 같이 state에 따라서 간선이 역방향, 정방향인지 정할 수 있고
각 state마다 인접 리스트(그래프)가 생성되게 됩니다.

이를 이용해 int dist[1025][1001] 배열을 선언하여
dist[state][node] : 현재 트랩의 상태가 state 일때, node까지의 최단 거리를 업데이트 해주는 BFS를
이용하여 end node까지의 거리를 구할 수 있습니다.
시간 제한이 10초로 넉넉하여 다익스트라를 사용하지 않고 일반 BFS를 사용하여도 AC를 받았습니다.

현재 노드가 cur 일때, 연결된 다음 노드 nxt가 트랩이라면 nxt에 연결된 간선이 뒤집어져야 하므로
state 비트를 변경해주어야 합니다. 간단히 bit xor 연산으로 다음 state를 구할 수 있습니다.
현재 state가 bit이고 nxt가 i번째 trap 이라면 next_bit = bit ^ (1<<i) 이 됩니다. i번째 bit만 뒤집어주면 되기 때문입니다.

다익스트라로 구현하면 end 노드에 처음 도착한 순간이 최단거리 이지만
BFS로 구현하였기 때문에 항상 최적의 경로로 방문하는 것이 아니어서
더이상 방문할 노드가 없을 때까지 계속 방문하며 최솟값을 업데이트 해주어야 합니다.

 

#include <string>
#include <vector>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <map>
using namespace std;
int dist[1025][1001];
bool trap[1001];
map<int,int> trapidx;
vector<pair<int,int>> adj[1025][1001];
bool isFlip(int a,vector<int>& flag){
    return trap[a] && flag[trapidx[a]];
}
int solution(int n, int start, int end, vector<vector<int>> roads, vector<int> traps) {
    for(int i=0;i<traps.size();i++) {
        trap[traps[i]]=1;
        trapidx[traps[i]]=i;
    }
    for(int i=0;i<(1<<traps.size());i++){
        vector<int> flag(traps.size(),0);
        for(int j=1;j<=n;j++) dist[i][j]=9e8;
        for(int j=0;j<traps.size();j++) {
            if(i&(1<<j)) flag[j]=1;
        }
        for(auto& r : roads){
            int u=r[0],v=r[1],c=r[2];
            int cnt = isFlip(u,flag)+isFlip(v,flag);
            if(cnt==1) adj[i][v].push_back({u,c});
            else adj[i][u].push_back({v,c});
        }
    }
    queue<pair<int,int>> q;
    dist[0][start]=0;
    q.push({0,start});

    int ans=9e8;
    while(!q.empty()){
        auto [bit,cur] = q.front(); q.pop();
        if(cur==end) ans=min(ans,dist[bit][cur]);
        for(auto [nxt,d] : adj[bit][cur]){
            int nb = bit;
            if(trap[nxt]) {
                int i = trapidx[nxt];
                nb ^= (1<<i);
            }
            if(dist[nb][nxt] > dist[bit][cur]+d){
                dist[nb][nxt]=dist[bit][cur]+d;
                q.push({nb,nxt});
            }
        }
    }
    return ans;
}


https://github.com/has2/Problem-Solving/blob/master/programmers/level4/미로_탈출.cpp

https://www.acmicpc.net/problem/1322

 

1322번: X와 K

첫째 줄에 X와 K가 주어진다. X와 K는 2,000,000,000보다 작거나 같은 자연수이다.

www.acmicpc.net

 

[난이도] Gold4
[유형] 비트마스크

[풀이]
X + Y = X | Y 를 만족하기 위해서는
Y를 2진수로 표현했을 때의 1은 X의 2진수가 0인 비트에만 넣을 수 있다. (반올림이 발생하기 때문에)
그러므로 K를 2진수로 표현했을 때의 비트를 하나씩 Y에서 비트가 0인 부분에 채워넣고, Y에서 비트가 1인 부분에는
0을 채워넣은 값이 정답이다.

 

#include <cstdio>
using ll = long long;
ll X,K,ret;
int main(){
    scanf("%lld%lld",&X,&K);
    int j=0;
    for(int i=0;;i++){
        if(!((X>>i)&1)){
            ret |= ((K>>j)&1) << i;
            j++;
            if(!(K>>j)) break;
        }
    }   
    printf("%lld",ret);
}



https://github.com/has2/Problem-Solving/blob/master/boj-solved.ac/Gold4/1322.cpp

https://www.acmicpc.net/problem/18119

 

18119번: 단어 암기

준석이는 영어 단어를 외우려고 한다. 사전에는 N가지 단어가 적혀 있다. 모든 단어는 소문자이다. 단어 안에 있는 모든 알파벳을 알 때, 그 단어를 완전히 안다고 한다. 다음과 같은 쿼리들이 주

www.acmicpc.net

[난이도] Gold4
[유형] 비트마스크

[풀이]
각 단어에 어떤 문자가 포함되어있는지만 기록하면 되므로 비트마스크를 이용해 현재 기억하고 있는
단어들과 O(NM)에 비교가 가능하다.

 

#include <iostream>
#include <string>
using namespace std;
int N,M,a[10001];
int main(){
    scanf("%d%d",&N,&M);
    for(int i=0;i<N;i++){
        string s;
        cin >> s;
        for(auto c : s) a[i] |= 1<<(c-'a');
    }
    int cur = (1<<26)-1;
    while(M--){
        int o,cnt=0;
        char x;
        cin >> o >> x;
        if(o==1) cur ^= 1<<(x-'a');
        else cur |= 1<<(x-'a');
        
        for(int i=0;i<N;i++){
            if(a[i] == (a[i]&cur)) cnt++;
        }
        cout << cnt << '\n';
    }
}



https://github.com/has2/Problem-Solving/blob/master/boj-solved.ac/Gold4/18119.cpp

www.acmicpc.net/problem/4991

 

4991번: 로봇 청소기

각각의 테스트 케이스마다 더러운 칸을 모두 깨끗한 칸으로 바꾸는 이동 횟수의 최솟값을 한 줄에 하나씩 출력한다. 만약, 방문할 수 없는 더러운 칸이 존재하는 경우에는 -1을 출력한다.

www.acmicpc.net

 

 

[난이도] Gold2

[유형] BFS,비트마스크

 

[풀이]

더러운 방의 최대 수가 10을 넘지 않기 때문에 현재까지 청소한 방을 의미하는 2^10을 visit 배열에 추가하여 3차원 bfs를 돌리면 된다.

#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
int w,h,sy,sx,dy[4]={-1,1,0,0},dx[4]={0,0,1,-1};
char map[20][20];
bool visit[20][20][1<<10];
struct P{
    int y,x,b;
};
vector<P> info;

int getPos(int y,int x){
    for(int i=0;i<info.size();i++){
        if(info[i].y==y&&info[i].x==x) return i;
    }
    return 0;
}
int bfs(){
    memset(visit,0,sizeof(visit));
    queue<P> q;
    visit[sy][sx][0]=1;
    q.push({sy,sx,0});
    int ret = 0;
    while(!q.empty()){  
        int qsz = q.size();
        while(qsz--){
            P qf = q.front(); q.pop();
            if(qf.b==(1<<info.size())-1) return ret;
            for(int i=0;i<4;i++){
                int ny = qf.y+dy[i],nx = qf.x+dx[i],bm = qf.b;
                if(ny < 0 || nx < 0 || ny >= h || nx >= w || map[ny][nx] == 'x') continue;
                if(map[ny][nx]=='*') bm |= (1<<getPos(ny,nx));
                if(!visit[ny][nx][bm]){
                    visit[ny][nx][bm] = 1;
                    q.push({ny,nx,bm});
                }
            }
        }
        ret++;
    }
    return -1;    
}

int main(){
    while(1){
        scanf("%d%d",&w,&h);
        if(w==0) break;
        info.clear();
        for(int i=0;i<h;i++){
            for(int j=0;j<w;j++){
                scanf(" %c",&map[i][j]);
                if(map[i][j]=='o'){
                    sy=i,sx=j;  
                }else if(map[i][j]=='*'){
                    info.push_back({i,j,0});
                }
            }
        }
        printf("%d\n",bfs());
    }
}

 

github.com/has2/Problem-Solving/blob/master/boj-solved.ac/Gold2/4991.cpp

+ Recent posts