読者です 読者をやめる 読者になる 読者になる

土下座しながら探索中

主に競技プログラミング

AOJ 1320 : City Merger

問題リンク:City Merger | Aizu Online Judge


解法:
巡回セールスマン問題みたいであった

cost[i][j] := 文字列jを文字列iの後ろにつなげてできる文字列の長さから文字列iの長さを引いた値

dp[1<

for i 0..n // 初期化 これ以外はinf 
  dp[1<<i][i] = s[i].length() //s[i] は 文字列i

for S i 0..(1<<n)-1
  for from 0..n //状態Sでfromからtoへ行く
    if !((S>>from) & 1) //まだfromを訪れていない
      continue
    for to 0..n
      if (S>>to) & 1 // もう既にtoは訪れた
        continue
      dp[S|(1<<to)][to] = min(dp[S|(1<<to)][to],
                              dp[S][from] + cost[from][to]

最終的な答えはdp[(1<

#include<iostream>
#include<vector>
#include<cassert>
#include<algorithm>
#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define inf (1<<29)
#define MAX 16
using namespace std;
 
int n;
int cost[MAX][MAX];
string s[MAX];
int dp[1<<MAX][MAX];
 
int getCost(string a,string b)
{//from a to b
  int res = inf;
  for(int i=a.size()-1,st = 0;i>=0 && st < b.size();i--,st++)
    {
      string ca = a.substr(i,a.size()-i);      
      string cb = b.substr(0,st+1);
      if(ca == cb)res = st+1; 
    }
  return res;
}
 
int main()
{
  while(cin >> n,n)
    {
      rep(i,n)rep(j,n)cost[i][j] = inf;
      rep(i,n)cin >> s[i];
      vector<string> ss;
      rep(i,n)
    {
      bool contain = false;
      rep(j,n)
        {
          if(i == j)continue;
          if(s[j].find(s[i]) != string::npos)
        {
 
          contain = true;
          break;
        }
        }
      if(!contain)ss.push_back(s[i]);
    }
 
      n = ss.size();
      rep(i,n)
    {
      rep(j,n)
        {
          if(i == j)
        {
          cost[i][j] = ss[i].size();
          continue;
        }
          int ct = getCost(ss[i],ss[j]);
          if(ct == inf)cost[i][j] = ss[j].size();
          else cost[i][j] = ss[j].size() - ct;
        }
    }
      rep(i,1<<n)rep(j,n)dp[i][j] = inf;
      rep(i,n)dp[1<<i][i] = ss[i].length();
 
      rep(S,(1<<n))
    {
      rep(from,n)
        {
          if(!((S>>from) & 1))continue;
          rep(to,n)
        {
          if((S>>to) & 1)continue;
          dp[S|(1<<to)][to] = min(dp[S|(1<<to)][to],
                      dp[S][from] + cost[from][to]);
        }
        }
    }
      int ans = inf;
      rep(i,n)ans = min(ans,dp[(1<<n)-1][i]);
 
      cout << ans << endl;
    }
  return 0;
}