poj初期数据结构


第三个专题了,初期数据结构:

(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
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值