SRM 381 500pt: TheHomework
問題概要
ふたつの集合A, Bが与えられる。集合Aに、値を加える、値を減らす、値を変えるなどの操作をして最短手数でBと等しくなるようにする問題。
後から考えたこと
- 何か全然やる気が出なくてさっさと答えを見てしまった…。
- 何があっているか、は重要ではなく、いくつ合っているか、が重要なので状態は(今の個数、合っている個数)で表される。
- 今の個数はあまり多くしても意味が無い。2*Nくらいあれば多分十分なので、状態数は全部で2*N^2くらい。
- もちろん全部の状態がvalidな訳ではない。
- で、ひとつの状態から遷移するのはN通りくらいなのでBFSで十分間に合う。
practiceで通ったコード
計算量O(N^3)。
#include <vector> #include <queue> #include <algorithm> using namespace std; const int INF = 1<<29; const int MAX_N = 55; int dist[2*MAX_N][MAX_N+1]; struct TheHomework { int transform(vector <int> first, vector <int> second) { int correct = 0, N = second.size(); //初期化 for(int i=0; i<2*MAX_N; i++){ fill(dist[i], dist[i]+MAX_N+1, INF); } //いくつ一致しているか数える for(int i=0; i<(int)first.size(); i++){ for(int j=0; j<(int)second.size(); j++){ if(first[i] == second[j]){ correct++; second[j] = -1; break; } } } queue< pair<int,int> > que; que.push( make_pair(first.size(), correct) ); dist[first.size()][correct] = 0; while(!que.empty()){ pair<int,int> tp = que.front(); que.pop(); int num = tp.first, cor = tp.second, nd = dist[num][cor] + 1; //増やす for(int a=1; a <= num; a++){ add(que, num+a, min(cor+a, N), nd); } //減らす for(int d=1; 2*d <= num; d++){ add(que, num-d, min(cor, num-d), nd); } //変える for(int c=1; 2*c <= num; c++){ add(que, num, min(cor+c, N), nd); } } return dist[N][N]; } void add(queue<pair<int,int> >& que, int num, int correct, int d){ if(num<0 || correct<0 || num >= 2*MAX_N || correct > MAX_N || dist[num][correct] != INF){ return ; } dist[num][correct] = d; que.push( make_pair(num, correct) ); } };