AOJ2061 International Party
問題リンク International Party
- 概要
N個の言語が飛び交うパーティーがあり、M個のグループがある。i番目のグループはki個の言語だけ使うことができる。パーティー全体で使用できる言語を最も小さくし、なおかつ任意の2グループ間でおしゃべりができるような言語の集合を答えよ。そのような集合が無かったり、必要最小数が5を超える場合は"Impossible"と答えよ。
1 <= N <= 30
2 <= M <= 20
1 <= ki <= 20
- 解法
全探索です。
使用を許す言語の組み合わせを全て試します。総数は 30C1 + 30C2 + 30C3 + 30C4 + 30C5 < 200000 程度です。
M個のグループを頂点とするグラフを作り、使うことを許された言語のみを使って、全頂点を連結できるかを深さ優先などで試します。
※グループiとjが i-k, k-jと繋がっているとき、グループkを翻訳係として、iとjはおしゃべりすることができます
- ソース
import java.util.HashMap; import java.util.Map; import java.util.Scanner; //International Party public class AOJ2061 { int n, m, INF = 1<<29, min; boolean[] u, v, res; boolean[][] e; int dfs(int k){ if(v[k])return 0; int res = 1; v[k] = true; for(int i=0;i<n;i++){ if(!u[i]||!e[k][i])continue; for(int j=0;j<m;j++)if(e[j][i])res += dfs(j); } return res; } void f(int k, int d){ if(5<d||min<=d)return; v = new boolean[m]; if(dfs(0)==m){ min = d; res = u.clone(); return; } for(int i=k;i<n;i++){ u[i] = true; f(i+1, d+1); u[i] = false; } } void run(){ Scanner sc = new Scanner(System.in); for(boolean h = true;;h=false){ n = sc.nextInt(); m = sc.nextInt(); if((n|m)==0)break; if(!h)System.out.println(); Map<String, Integer> ref = new HashMap<String, Integer>(); String[] s = new String[n]; for(int i=0;i<n;i++){ s[i] = sc.next(); ref.put(s[i], i); } e = new boolean[m][n]; for(int i=0;i<m;i++){ int k = sc.nextInt(); while(k--!=0)e[i][ref.get(sc.next())] = true; } u = new boolean[n]; min = INF; f(0, 0); if(min==INF)System.out.println("Impossible"); else { System.out.println(min); for(int i=0;i<n;i++)if(res[i])System.out.println(s[i]); } } } public static void main(String[] args) { new AOJ2061().run(); } }