第三个专题了,初期数据结构:
(1)、串
1、poj1035
题意:给定一个字典,再给你一些字符串,如果字典中有这个字符串,则直接输出,如果没有的话,那就找字符串加一个字符或少一个字符或者换一个字符是否可以在字典中找到相应的字符串。
分析:水题,直接暴力。。。
#include <cstdio>
#include <cstring>
char s[10010][20], str[60][20], temp[20];
void Replace(char s[][20], char str[][20], int snum, int strnum) {
int Len, len, tag, flag, Tag;
int i, j, x, y;
for (y = 0; y < strnum; y++) {
flag = 1;
for (i = 0; i < snum; i++) {
if (strcmp(s[y], str[i]) == 0) {
flag = 0;
printf("%s is correct\n", s[y]);
break;
}
}
if (!flag) continue;
printf("%s:", s[y]);
for (i = 0; i < snum; i++) {
len = strlen(s[y]);
Len = strlen(str[i]);
if (len == Len) {
tag = 0;
for (x = 0; x < len && tag != 2; x++) {
if (str[i][x] != s[y][x]) tag++;
}
if (tag == 1) printf(" %s", str[i]);
continue;
}
if (Len+1 == len || Len == len+1) {
int min = Len>len?len:Len;
int max = Len>len?Len:len;
flag = 1;
for (x = 0; x < min && flag; x++) {
if (s[y][x] != str[i][x]) flag = 0;
}
if (flag) printf(" %s", str[i]);
else {
for (x = 0; x < min; x++) {
tag = Tag = 1;
for (j = 0; j < max && tag; j++) {
if (j == x) {
Tag = 0;
continue;
}
if (Tag) {
if (str[i][j] != s[y][j]) tag = 0;
}
else {
if (Len < len) {
if (str[i][j-1] != s[y][j]) tag = 0;
}
else {
if (str[i][j] != s[y][j-1]) tag = 0;
}
}
}
if (tag) {
printf(" %s", str[i]);
break;
}
}
}
}
}
puts("");
}
}
int main() {
int i = 0, j = 0, x, y;
while (scanf("%s", temp), strcmp("#", temp) != 0) strcpy(s[i++], temp);
while (scanf("%s", temp), strcmp("#", temp) != 0) strcpy(str[j++], temp);
Replace(str, s, i, j);
return 0;
}
2、poj3080
题意:求n个字符串的最长公共串。
分析:直接暴力,水题。。。
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 70;
const int LEN = 60;
char s[15][N], str[N], ans[N];
bool check(int n) {
for (int i = 1; i < n; i++)
if (!strstr(s[i], str)) return 0;
return 1;
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) scanf("%s", s[i]);
memset(ans, 0, sizeof(ans));
int ma = 0;
for (int i = 0; i <= LEN - ma; i++) {
int t = ma;
copy(s[0]+i, s[0]+i+t, str);
str[t] = 0;
for (int j = i+t; j <= LEN; j++) {
if (check(n)) {
if ((t == ma && strcmp(str, ans) < 0) || t > ma) strcpy(ans, str), ma = t;
}
else break;
str[t] = s[0][j]; str[++t] = 0;
}
}
puts(strlen(ans) < 3 ? "no significant commonalities" : ans);
}
return 0;
}
3、poj1936
题意:求一个串是不是包含于另一个串中,且相对位置不变。
分析:直接暴力,复杂度最多为O(strlen(s1)+ strlen(s2))。
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
const int N = 100005;
char s[N], str[N];
int len;
bool cal(int &pos, int i) {
for (; pos < len; pos++)
if (s[pos] == str[i]) { pos++; return 1; }
return 0;
}
int main() {
while (~scanf("%s %s", str, s)) {
len = strlen(s);
int p = 0, l = strlen(str);
if (l > len) { puts("No"); continue; }
if (l == len) { puts(strcmp(s, str) == 0 ? "Yes" : "No"); continue; }
int flag = 1;
for (int i = 0; i < l && flag; i++)
if (p == len || !cal(p, i)) flag = 0;
puts(flag ? "Yes" : "No");
}
return 0;
}
(2)、排序
1、poj2388
题意:求一个序列最中间的数。
分析:nth_element,复杂度为O(n),不需要给数组排序。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 10005;
int a[N];
int main() {
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) scanf("%d", &a[i]);
nth_element(a, a+n/2, a+n);
printf("%d\n", a[n/2]);
return 0;
}
2、poj2299
题意:说那么多,就是求逆序数。
分析:不能暴力,树状数组和归并排序都可以,然而我这种蒟蒻不会树状数组。。。
#include <cstdio>
#include <algorithm>
#include <cctype>
using namespace std;
typedef long long LL;
const int N = 500005;
int a[N], b[N];
template <class T>
inline void read(T &res) {
char c; res = 0;
while (!isdigit(c = getchar()));
while (isdigit(c)) res = res * 10 + c - '0', c = getchar();
}
LL Merge(int* a, int l, int r) {
if (l >= r) return 0;
int m = (l + r) / 2;
LL cnt = Merge(a, l, m);
cnt += Merge(a, m + 1, r);
int i = l, j = m + 1, x = 0, y;
while (i <= m && j <= r) {
if (a[i] <= a[j]) b[x++] = a[i++];
else b[x++] = a[j++], cnt += m - i + 1;
}
if (i <= m) copy(a + i, a + m + 1, b + x);
else if (j <= r) copy(a + j, a + r + 1, b + x);
copy(b, b + r - l + 1, a + l);
return cnt;
}
int main() {
int n;
while (scanf("%d", &n), n) {
for (int i = 1; i <= n; i++) read(a[i]);
printf("%I64d\n", Merge(a, 1, n));
}
return 0;
}
(3)、并查集的基础应用
第一次做并查集的题,粗略学了下并查集。
这里分类上面没给题,自己找了几个题做做。
1、poj 1611
题意:有一个学校,有N个学生,编号为0-N-1,现在0号学生感染了非典,凡是和0在一个社团的人就会感染,并且这些人如果还参加了别的社团,他所在的社团照样全部感染,求感染的人数。
分析:简单并查集,求包含0号学生的联通分支的个数,在路径压缩的同时统计人数,最后输出0号学生所在根节点的数目即可。
#include <cstdio&g