24h購物| | PChome| 登入
2013-12-27 20:40:13| 人氣2,660| 回應0 | 上一篇 | 下一篇

[数据结构与算法] 第11周 检索 作业题

推薦 0 收藏 0 轉貼0 訂閱站台

1:拼写检查

描述
现在有一些英语单词需要做拼写检查,你的工具是一本词典。需要检查的单词,有的是词典中的单词,有的与词典中的单词相似,你的任务是发现这两种情况。单词A与单词B相似的情况有三种:
1、删除单词A的一个字母后得到单词B;
2、用任意一个字母替换单词A的一个字母后得到单词B;
3、在单词A的任意位置增加一个字母后得到单词B。
你的任务是发现词典中与给定单词相同或相似的单词。


输入
第一部分是词典中的单词,从第一行开始每行一个单词,以"#"结束。词典中的单词保证不重复,最多有10000个。
第二部分是需要查询的单词,每行一个,以"#"结束。最多有50个需要查询的单词。
词典中的单词和需要查询的单词均由小写字母组成,最多包含15个字符。
输出
按照输入的顺序,为每个需要检查的单词输出一行。如果需要检查的单词出现在词典中,输出“?x is correct",?x代表需要检查的单词。如果需要检查的单词没有出现在词典中,则输出"?x: ?x1 ?x2 ...?xn",其中?x代表需要检查的单词,?x1...?xn代表词典中与需要检查的单词相似的单词,这些单词中间以空格隔开。如果没有相似的单词, 输出"?x:"即可。
样例输入
i
is
has
have
be
my
more
contest
me
too
if
award
#
me
aware
m
contest
hav
oo
or
i
fi
mre
#
样例输出
me is correct
aware: award
m: i my me
contest is correct
hav: has have
oo: too
or:
i is correct
fi: i
mre: more me

窮舉刪除位置、插入位置、替換字元,然後到 set 中去查找字串。

刪除位置窮舉 O(len)

插入位置窮舉 O(len * 26)

替換字元窮舉 O(len * 26)

#include <stdio.h>
#include <iostream>
#include <set>
#include <string.h>
#include <map>
using namespace std;
char word[10005][20], s[20];
int wlen[10005];
set<string> S[20];
map<string, int> M;
int main() {
    int n = 0;
    int i, j, k;
    while(scanf("%s", &word[n]) == 1) {
        if(!strcmp(word[n], "#"))
            break;
        wlen[n] = strlen(word[n]);
        S[wlen[n]].insert(word[n]);
        M[word[n]] = n;
        n++;
    }
    while(scanf("%s", s) == 1) {
        if(!strcmp(s, "#"))
            break;
        int len = strlen(s);
        if(S[len].find(s) != S[len].end()) {
            printf("%s is correct\n", s);
            continue;
        }
        printf("%s:", s);
        char err[20];
        for(i = 1; i < len; i++)
            err[i-1] = s[i];
        err[len-1] = '\0';
        set<string> ret;
        for(i = 0; i < len; i++) {
            if(S[len-1].find(err) != S[len-1].end())
                ret.insert(err);
            err[i] = s[i];
        }
        for(i = 0; i < len; i++)
            err[i] = s[i];
        err[len] = '\0';
        for(i = 0; i < len; i++) {
            for(j = 'a'; j <= 'z'; j++) {
                if(j == s[i])    continue;
                err[i] = j;
                if(S[len].find(err) != S[len].end())
                    ret.insert(err);
            }
            err[i] = s[i];
        }   
        for(i = 0; i < len; i++)
            err[i+1] = s[i];   
        err[len+1] = '\0';
        for(i = 0; i <= len; i++) {
            for(j = 'a'; j <= 'z'; j++) {
                err[i] = j;
                if(S[len+1].find(err) != S[len+1].end())
                    ret.insert(err);
            }
            err[i] = s[i];
        }
        set<int> R;
        for(set<string>::iterator it = ret.begin();
            it != ret.end(); it++) {
            R.insert(M[*it]);
        }
        for(set<int>::iterator it = R.begin();
            it != R.end(); it++)
            printf(" %s", word[*it]);
        puts("");
    }
    return 0;
}

2:正方形


描述
给定直角坐标系中的若干整点,请寻找可以由这些点组成的正方形,并统计它们的个数。
输入
包括多组数据,每组数据的第一行是整点的个数n(1<=n<=1000),其后n行每行由两个整数组成,表示一个点的x、y坐标。输入保证一组数据中不会出现相同的点,且坐标的绝对值小于等于20000。输入以一组n=0的数据结尾。
输出
对于每组输入数据,输出一个数,表示这组数据中的点可以组成的正方形的数量。
样例输入
4
1 0
0 1
1 1
0 0
9
0 0
1 0
2 0
0 2
1 2
2 2
0 1
1 1
2 1
4
-2 5
3 7
0 0
5 2
0
样例输出
1
6
1 

任抓兩點窮舉,拉出一個正方形,快速查找另外兩點。

考慮只向單邊進行增加,找到另外兩點。

對於窮舉的兩點得到線的法向量,再對這兩點走法向量分別拉出相對應的兩點。

#include <stdio.h>
#include <set>
#include <algorithm>
using namespace std;
struct Pt {
    int x, y;
    Pt(int a=0, int b=0):
        x(a), y(b) {}
    bool operator<(const Pt &a) const {
        if(x != a.x)
            return x < a.x;
        return y < a.y;
    }
};
int main() {
    int n;
    int i, j, k;
    Pt D[1005];
    while(scanf("%d", &n) == 1 && n) {
        for(i = 0; i < n; i++)
            scanf("%d %d", &D[i].x, &D[i].y);
        sort(D, D+n);
        int ret = 0;
        set<int> S[40005];
        for(i = 0; i < n; i++)
            S[D[i].x+20000].insert(D[i].y);
        int x, y;
        for(i = 0; i < n; i++) {
            for(j = i+1; j < n; j++) {
                int dx = D[j].x - D[i].x;
                int dy = D[j].y - D[i].y;
                x = D[i].x - dy;
                y = D[i].y + dx;
                if(-dy < 0)    continue;
                if(x + 20000 < 0 || x + 20000 >= 40005)
                    continue;
                if(S[x+20000].find(y) == S[x+20000].end())
                    continue;
                x = D[j].x - dy;
                y = D[j].y + dx;
                if(x + 20000 < 0 || x + 20000 >= 40005)
                    continue;
                if(S[x+20000].find(y) == S[x+20000].end())
                    continue;/*
                printf("%d %d\n", D[i].x, D[i].y);
                printf("%d %d\n", D[j].x, D[j].y);
                printf("%d %d\n", x, y);
                printf("x ------ %d %d\n", dx, dy);*/
                ret++;
            }
        }
        printf("%d\n", ret);
    }
    return 0;
}

3:发现它,抓住它


描述
一 个城市中有两个犯罪团伙A和B,你需要帮助警察判断任意两起案件是否是同一个犯罪团伙所为,警察所获得的信息是有限的。假设现在有N起案件 (N<=100000),编号为1到N,每起案件由团伙A或团伙B所为。你将按时间顺序获得M条信息(M<=100000),这些信息分为两 类:
1. D [a] [b]
其中[a]和[b]表示两起案件的编号,这条信息表明它们属于不同的团伙所为

2. A [a] [b]
其中[a]和[b]表示两起案件的编号,这条信息需要你回答[a]和[b]是否是同一个团伙所为
注意你获得信息的时间是有先后顺序的,在回答的时候只能根据已经接收到的信息做出判断。


输入
第一行是测试数据的数量T(1<=T<=20)。
每组测试数据的第一行包括两个数N和M,分别表示案件的数量和信息的数量,其后M行表示按时间顺序收到的M条信息。
输出
对于每条需要回答的信息,你需要输出一行答案。如果是同一个团伙所为,回答"In the same gang.",如果不是,回答"In different gangs.",如果不确定,回答”Not sure yet."。
样例输入
1
5 5
A 1 2
D 1 2
A 1 2
D 2 4
A 1 4
样例输出
Not sure yet.
In different gangs.
In the same gang. 

相當不錯的一個題目。

使用一個 併查集 和 陣列 維護,這個陣列記住與它相對的事件。

因此倘若又發生不同的事件,可以將對方已知的相對事件與自己做合併動作。

因為它必然是相同的。


#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int parent[100005], AB[100005]; // opposite AB
int findp(int x) {
    return parent[x] == x ? x : (parent[x]=findp(parent[x]));
}
int joint(int x, int y) {
    x = findp(x), y = findp(y);
    parent[x] = y;
}
int main() {
    int testcase;
    int n, m, a, b, i;
    char s[20];
    scanf("%d", &testcase);
    while(testcase--) {
        scanf("%d %d", &n, &m);
        for(i = 1; i <= n; i++) {
            parent[i] = i;
            AB[i] = 0;
        }
        for(i = 0; i < m; i++) {
            scanf("%s %d %d", s, &a, &b);
            if(s[0] == 'D') {
                if(AB[a] == 0 && AB[b] == 0)
                    AB[a] = b, AB[b] = a;
                else if(AB[a] == 0) {
                    AB[a] = b;
                    joint(a, AB[b]);
                } else if(AB[b] == 0) {
                    AB[b] = a;
                    joint(b, AB[a]);
                } else {
                    joint(a, AB[b]);
                    joint(b, AB[a]);
                }
            } else {
                if(findp(a) == findp(b))
                    puts("In the same gang.");
                else if(findp(a) == findp(AB[b]))
                    puts("In different gangs.");
                else
                    puts("Not sure yet.");
            }
        }
    }
    return 0;
}

台長: Morris
人氣(2,660) | 回應(0)| 推薦 (0)| 收藏 (0)| 轉寄
全站分類: 教育學習(進修、留學、學術研究、教育概況) | 個人分類: 其他題目 |
此分類下一篇:[数据结构与算法] 第12周 索引技术 作业题
此分類上一篇:[高等演算法] 雜

是 (若未登入"個人新聞台帳號"則看不到回覆唷!)
* 請輸入識別碼:
請輸入圖片中算式的結果(可能為0) 
(有*為必填)
TOP
詳全文