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
- 1≤number of test cases≤6
- 1≤N≤1000
- 1≤length of each block≤1000
- 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 }