Joining Byte Blocks(哈希+带花树)

题目链接

Problem Statement

As you are probably aware, the Internet protocols specify a canonical byte order convention for data transmitted over the network called network byte order, so that machines with different byte order conventions can communicate. But what if such canonical byte order didn't exist? We would probably be trapped in chaos trying to figure out the byte order for every machine we want to communicate with. But luckily, no matter the byte order (big-endian or little-endian), there will be byte blocks that will always be read correctly. 

Imagine you have a list of N byte blocks. In order to minimize the number of trasmission operations required to send all of them, you want to pair as many as possible blocks. Note that the resulting byte frame should have same representation in both network orders, i.e., they should be a palindrome when paired. The rules for such pairings are the following:

  • No block can be paired with itself.
  • A block can be paired zero or one time.
  • You cannot pair more than two blocks.

For the ease of representation we will use lowercase latin characters to represent byte blocks. Suppose we have two blocks [a,a,f] and [f], and they are paired to form the frame [f,a,a,f], then it has the same representation in any of the byte order. 

Now, given the list of blocks, using the pairings described above, what's the minimum number of transmissions required to send them all?

Note: A block can either be transmitted alone, or paired with another block (if the pair satisfies above criteria).

Input Format

There will be multiple test cases per input file. Every test case will start with a number Ntelling you the size of the list. Then N lines follow, each one with a block, where each byte has been replaced by its current English alphabet lowercase letter. No test case will have more than 3000 potential pairs.

Output Format

Output a single line per test case in the input with the required answer.

Constraints

  • 1number of test cases6
  • 1N1000
  • 1length of each block1000
  • Each block consisits of lowercase latin characters, [a,z].

Sample Input

6

aaababa

aa

ababaaa

baaa

a

b

9

aabbaabb 

bbaabbaa

aa

bb

a

bbaa

bba

bab

ab

Sample Output

3

5

Explanation

  • Sample Case #00: All of the blocks can be paired into following 3 frames.

    • "baaa" + "b" = "baaab"
    • "aaababa + "ababaaa" = "aaababaababaaa"
    • "aa" + "a" = "aaa"
  • Sample Case #01: Following frames will be sent

    • "aabbaabb" + "bbaabbaa" = "aabbaabbbbaabbaa"
    • "aa" + "a = "aaa"
    • "bba" + "bb" = "bbabb"
    • "bab" + "ab" = "babab"
    • "bbaa"

又一个之前没有用过的字符串hash的应用。还加了个一般图最大匹配的模板。

AC代码:

  1 #include<set>

  2 #include<map>

  3 #include<cmath>

  4 #include<queue>

  5 #include<cstdio>

  6 #include<vector>

  7 #include<string>

  8 #include<cstdlib>

  9 #include<cstring>

 10 #include<iostream>

 11 #include<algorithm>

 12 using namespace std;

 13 

 14 #define mem(a, b) (memset(a, b, sizeof(a)))

 15 #define pb push_back

 16 #define all(v) v.begin(), v.end()

 17 #define rall(v) v.rbegin(), v.rend()

 18 #define rep(i, m) for (int i = 0; i < (int)(m); i++)

 19 #define rep2(i, n, m) for (int i = n; i < (int)(m); i++)

 20 typedef long long LL;

 21 typedef pair<LL, LL> PLL;

 22 

 23 const int oo = (int) 1e9;

 24 const double PI = 2 * acos(0);

 25 const double eps = 1e-9;

 26 const int MAX_N = 2048;

 27 

 28 const int P = 131;

 29 const int Q = 191;

 30 const int MP = 1000003;

 31 const int MQ = 10000019;

 32 LL pw[MAX_N], qw[MAX_N];

 33 char str[MAX_N];

 34 #define F first

 35 #define S second

 36 

 37 /* 采用两个hash函数*/

 38 struct strHash {

 39     PLL str, rev;

 40     int len;

 41 

 42     strHash operator +(const strHash &o) const {

 43         strHash res;

 44         res.str.F = (str.F * pw[o.len] + o.str.F) % MP;

 45         res.str.S = (str.S * qw[o.len] + o.str.S) % MQ;

 46         res.rev.F = (o.rev.F * pw[len] + rev.F) % MP;

 47         res.rev.S = (o.rev.S * qw[len] + rev.S) % MQ;

 48         res.len = len + o.len;

 49         return res;

 50     }

 51 }s[MAX_N];

 52 

 53 void init() {

 54     pw[0] = qw[0] = 1;

 55     for (int i = 1; i < MAX_N; i++) {

 56         pw[i] = pw[i-1] * P % MP;

 57         qw[i] = qw[i-1] * Q % MQ;

 58     }

 59 }

 60 

 61 strHash makeHash(const char *str) {

 62     strHash res;

 63     res.len = strlen(str);

 64     res.str.F = res.str.S = 0;

 65     for (int i = 0; i < res.len; i++) {

 66         res.str.F = (res.str.F * P + str[i]) % MP;

 67         res.str.S = (res.str.S * Q + str[i]) % MQ;

 68     }

 69     res.rev.F = res.rev.S = 0;

 70     for (int i = res.len-1; ~i; i--) {

 71         res.rev.F = (res.rev.F * P + str[i]) % MP;

 72         res.rev.S = (res.rev.S * Q + str[i]) % MQ;

 73     }

 74     return res;

 75 }

 76 

 77 /* 判断a+b 或者 b+a是否为回文 */

 78 inline bool check(const strHash &a, const strHash &b) {

 79     strHash u = a + b;

 80     if (u.str == u.rev) return true;

 81     strHash v = b + a;

 82     if (v.str == v.rev) return true;

 83     return false;

 84 }

 85 

 86 

 87 /* 一般图最大匹配(带花树) */

 88 const int MAX = 2048;

 89 struct GraphMatch {

 90   int Next[MAX];

 91   int spouse[MAX];

 92   int belong[MAX];

 93 

 94   int findb(int a) {

 95     return belong[a]==a?a:belong[a]=findb(belong[a]);

 96   }

 97   void together(int a,int b){

 98     a=findb(a),b=findb(b);

 99     if (a!=b)belong[a]=b;

100   }

101 

102   vector<int> E[MAX];

103   int N;

104   int Q[MAX],bot;

105   int mark[MAX];

106   int visited[MAX];

107 

108   int findLCA(int x,int y){

109     static int t=0;

110     t++;

111     while (1) {

112       if (x!=-1) {

113               x = findb(x);

114               if (visited[x]==t)return x;

115               visited[x]=t;

116               if (spouse[x]!=-1)x=Next[spouse[x]];

117               else x=-1;

118           }

119           swap(x,y);

120       }

121   }

122 

123   void goup(int a,int p){

124     while (a!=p){

125           int b=spouse[a],c=Next[b];

126           if (findb(c)!=p)Next[c]=b;

127           if (mark[b]==2)mark[Q[bot++]=b]=1;

128           if (mark[c]==2)mark[Q[bot++]=c]=1;

129           together(a,b);

130           together(b,c);

131           a=c;

132       }

133   }

134 

135     void findaugment(int s){

136       for (int i=0;i<N;i++) {

137           Next[i]=-1;

138           belong[i]=i;

139           mark[i]=0;

140           visited[i]=-1;

141       }

142       Q[0]=s;bot=1;mark[s]=1;

143       for (int head=0;spouse[s]==-1 && head<bot;head++){

144           int x=Q[head];

145           for (int i=0;i<(int)E[x].size();i++){

146                 int y=E[x][i];

147                 if (spouse[x]!=y && findb(x)!=findb(y) && mark[y]!=2){

148                     if (mark[y]==1){

149                         int p=findLCA(x,y);

150                         if (findb(x)!=p)Next[x]=y;

151                         if (findb(y)!=p)Next[y]=x;

152                         goup(x,p);

153                         goup(y,p);

154                     }else if (spouse[y]==-1){

155                         Next[y]=x;

156                         for (int j=y;j!=-1;){

157                             int k=Next[j];

158                             int l=spouse[k];

159                             spouse[j]=k;spouse[k]=j;

160                             j=l;

161                         }

162                         break;

163                     }else{

164                         Next[y]=x;

165                         mark[Q[bot++]=spouse[y]]=1;

166                         mark[y]=2;

167                     }

168                 }

169             }

170         }

171     }

172 

173     void init(int n) {

174       N = n;

175       for (int i = 0; i < N; ++i) {

176         E[i].clear();

177       }

178     }

179 

180     void addEdge(int a, int b) {

181       E[a].push_back(b);

182       E[b].push_back(a);

183     }

184 

185     int maxMatch() {

186       int ret = 0;

187       for (int i = 0; i < N; ++i) spouse[i] = -1;

188       for (int i = 0; i < N; ++i) {

189         if (spouse[i] == -1) {

190           findaugment(i);

191         }

192       }

193       for (int i = 0; i < N; ++i) {

194         if (spouse[i] != -1) ++ret;

195       }

196       return ret;

197     }

198 } match;

199 

200 

201 int main(void) {

202     init();

203     int N;

204     while (~scanf("%d", &N)) {

205         for (int i = 0; i < N; i++) {

206             scanf("%s", str);

207             s[i] = makeHash(str);

208         }

209 

210         match.init(N);

211         for (int i = 0; i < N; i++) {

212             for (int j = i+1; j < N; j++) {

213                 if (check(s[i], s[j])) {

214                     match.addEdge(i, j);

215                 }

216             }

217         }

218         int cnt = match.maxMatch();

219         /*

220          for (int i = 0; i < N; i++) {

221              printf("%d %d\n", i, match.spouse[i]);

222          }

223          */

224         printf("%d\n", N - cnt / 2);

225     }

226 

227     return 0;

228 }
View Code

 

你可能感兴趣的:(block)