PalindromeGame srm 499 div2 hard

方針

最大の得点を達成するカードの組み合わせの中には、与えられたカードの中で最大の得点を持つカードと、そのカードの文字列を逆にした文字列を持つカードの中で最大の得点を持つカードが必ず含まれる。何故なら、これを満たさない組み合わせがあった時、これを満たすように変更すれば、得点が上がるから。この方針を、素直に実装。

答案

但し、システムテスト通らず。。。

front = { "abc", "cba", "def", "abc", "fed" }
back = { 24, 7, 63, 222, 190 }

のケースでこけた。手元の環境では正しい答えなんだけどなぁ。原因は不明。誰か分かったら教えてください。
2011-03-20 追記 : バグ修正。edgeの初期化時に、falseで埋めるのを忘れていた。

#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <iostream>
#include <utility>
#include <set>
#include <cctype>
#include <queue>
#include <stack>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iterator>



using namespace std;

string reverse(const string& s){
  string ret = s;
  int n = (int)s.size();
  for(int i = 0; i < n; i++){
    ret[i] = s[n - 1 - i];
  }
  return ret;
}

class PalindromeGame{
public:
  int n;
  vector<string> rev;
  vector<vector<bool> > edge;
  vector<bool> used;

  int getMaximum(vector <string> front, vector <int> back){
    n = (int)front.size();
    rev.resize(n);
    for(int i = 0; i < n; i++){
      rev[i] = reverse(front[i]);
    }

    edge.resize(n);
    for(int i = 0; i < n; i++){
      edge[i].resize(n);
      fill(edge[i].begin(), edge[i].end(), false);
    }

    for(int i = 0; i < n; i++){
      for(int j = i + 1; j < n; j++){
	edge[j][i] = edge[i][j] = front[i] == rev[j];
      }
    }

    used.resize(n);
    fill(used.begin(), used.end(), false);

    long long ret = 0;
    while(true){
      printEdge();
      int ii, imax = 0;
      for(int i = 0; i < n; i++){
	if(hasEdge(i) && imax < back[i]){
	  imax = back[i];
	  ii = i;
	}
      }

      if(imax == 0) break;

      int jj, jmax = 0;
      for(int j = 0; j < n; j++){
	if(edge[ii][j] && jmax < back[j]){
	  jmax = back[j];
	  jj = j;
	}
      }

      ret += imax;
      ret += jmax;
      remove(ii);
      remove(jj);
      used[ii] = used[jj] = true;
    }

    int ii, imax = 0;
    for(int i = 0; i < n; i++){
      if(!used[i] && front[i] == rev[i]){
	ii = i;
	imax = max(imax, back[i]);
      }
    }
    if(imax > 0){
      used[ii] = true;
      ret += imax;
    }

    return ret;
  }

  void printEdge(){
    cout << "----" << endl;
    for(int i = 0; i < n; i++){
      for(int j = 0; j < n; j++){
	cout << edge[i][j] << " ";
      }
      cout << endl;
    }
    cout << "----" << endl;
  }

  bool hasEdge(int i){
    for(int j = 0; j < n; j++){ 
      if(edge[i][j]) return true;
    }
    return false;
  }

  void remove(int i){
    fill(edge[i].begin(), edge[i].end(), false);
    for(int j = 0; j < n; j++){
      edge[j][i] = false;
    }
  }


};