Problem 2026 : Divisor is the Conqueror
Problem D: Divisor is the Conqueror
http://rose.u-aizu.ac.jp/onlinejudge/ProblemSet/description.jsp?id=2026
- 問題概要
カードが52枚以下、13までの数がかいてある。
カードを全部取れればそのとり方、取れなければNoをだせ。
取るルールは
1 最初はなんでも取っていい。
2 次からは、今までとったカードの合計を割ることのできるカードのみ取ってよい。
- 解法
DFS。
ただし、状態がすんごいおおい(52!/(13!*4)くらい?)ので普通にやると終わらない。
逆からやると終わる。
多分候補が少なくなるから?
多分そうだと思うけど、証明できない。
でも逆からやると終わります。
- ソース
#include<iostream> #include<string> #include<algorithm> #include<vector> #include<map> #include<set> #include<cstdlib> #include<cstdio> #include<cmath> #include<sstream> #include<cassert> #include<queue> #include<stack> #define REP(i,b,n) for(int i=b;i<n;i++) #define rep(i,n) REP(i,0,n) #define ALL(C) (C).begin(),(C).end() #define pb push_back #define mp make_pair #define vint vector<int> #define FOR(it,o) for(__typeof((o).begin()) it=(o).begin(); it!=(o).end(); ++it) #define lli long long int #define ld long double using namespace std; int c[14], n; bool end; void saiki(int sum, stack<int> st){ if(st.size() == n){ end = true; bool first = true; while(!st.empty()){ if(!first)cout << ' '; first = false; cout << st.top(); st.pop(); } cout << endl; return; } rep(i, 14){ if(c[i] == 0)continue; if((sum - i) % i != 0)continue; st.push(i); c[i]--; saiki(sum-i, st); if(end)return; c[i]++; st.pop(); } } main(){ while(cin >> n){ if(n == 0)break; rep(i, 14){ c[i] = 0; } int sum = 0; rep(i, n){ int tmp; cin >> tmp; sum += tmp; c[tmp]++; } end = false; rep(i, 14){ if(c[i] == 0)continue; if((sum - i) % i != 0)continue; c[i]--; stack<int> st; st.push(i); saiki(sum-i, st); if(end)break; c[i]++; } if(!end)cout << "No" << endl; } }