USACO Section 3.1 Contact(map)

本文探讨了ContactIOI'98题目,该题目要求在0和1组成的字符串中找出长度在A到B之间的最频繁出现的子串,并按频率、长度及字典序输出前N个子串。文章提供了两种解决策略的代码实现,分析了它们的优劣。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Contact
IOI'98

The cows have developed a new interest in scanning the universe outside their farm with radiotelescopes. Recently, they noticed a very curious microwave pulsing emission sent right from the centre of the galaxy. They wish to know if the emission is transmitted by some extraterrestrial form of intelligent life or if it is nothing but the usual heartbeat of the stars.

Help the cows to find the Truth by providing a tool to analyze bit patterns in the files they record. They are seeking bit patterns of length A through B inclusive (1 <= A <= B <= 12) that repeat themselves most often in each day's data file. They are looking for the patterns that repeat themselves most often. An input limit tells how many of the most frequent patterns to output.

Pattern occurrences may overlap, and only patterns that occur at least once are taken into account.

PROGRAM NAME: contact

INPUT FORMAT

Line 1:Three space-separated integers: A, B, N; (1 <= N < 50)
Lines 2 and beyond:A sequence of as many as 200,000 characters, all 0 or 1; the characters are presented 80 per line, except potentially the last line.

SAMPLE INPUT (file contact.in)

2 4 10
01010010010001000111101100001010011001111000010010011110010000000

In this example, pattern 100 occurs 12 times, and pattern 1000 occurs 5 times. The most frequent pattern is 00, with 23 occurrences.

OUTPUT FORMAT

Lines that list the N highest frequencies (in descending order of frequency) along with the patterns that occur in those frequencies. Order those patterns by shortest-to-longest and increasing binary number for those of the same frequency. If fewer than N highest frequencies are available, print only those that are.

Print the frequency alone by itself on a line. Then print the actual patterns space separated, six to a line (unless fewer than six remain).

SAMPLE OUTPUT (file contact.out)

23
00
15
01 10
12
100
11
11 000 001
10
010
8
0100
7
0010 1001
6
111 0000
5
011 110 1000
4
0001 0011 1100
题意:用 0 和 1 组成一个字符串str,求子串重复最多的前n种,子串的长度是[A,B],两个字符串重复的数一样,属于同一种。输出格式字符串长度小的优先,然后字典序小的优先。
分析:对于每个子串,用map映射一下,然后枚举字符串str。
策略一:用BFS初始map<string,int>m,然后再枚举。
策略二:直接开始枚举,然后碰见一个字符串,直接放进map中,让其自加。
杂一看明显策略二优于策略一,可是事实却是相反的,想一下还是可以理解的。策略一首先把map建好,每次映射直接找就行了;策略二每次映射时先要判断一下,如果没有再建一个,最后在映射一下。由于字符串中只有0和1,所以map中的结点也会接近2^(B+1)。所以慢性也是正常的。
策略一:
View Code
/*
  ID: dizzy_l1
  LANG: C++
  TASK: contact
*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdio>
#include<map>
#define MAXN 200010

using namespace std;

map<string,int>m;
map<string,bool>flag;
char s[15],str[MAXN],tstr[100];
struct ANS
{
    string as;
    int ac;
}ans[500];

void DFS(int n,int p)
{
    if(p==n)
    {
        m[s]=0;
        flag[s]=false;
        return ;
    }
    s[p]='0';s[p+1]='\0';
    DFS(n,p+1);
    s[p]='1';s[p+1]='\0';
    DFS(n,p+1);
}

void Init(int A,int B)
{
    for(int i=A; i<=B; i++) DFS(i,0);
}

bool cmp(ANS A,ANS B)
{
    if(A.ac<B.ac) return true;
    if(A.ac==B.ac&&A.as<B.as) return true;
    return false;
}

int main()
{
    freopen("contact.in","r",stdin);
    freopen("contact.out","w",stdout);
    int A,B,n,len,i,j,k,cnt,Max;
    string ts;
    scanf("%d%d%d",&A,&B,&n);
    m.clear();
    flag.clear();
    Init(A,B);
    while(scanf("%s",tstr)!=EOF) strcat(str,tstr);
    len=strlen(str);
    for(i=0; i<len; i++)//枚举所以的值映射到map中
    {
        j=0;
        k=i;
        ts="";
        while(j<A&&k<=len) ts+=str[k++],j++;
        while(j<=B&&k<=len)
        {
            m[ts]++;
            ts+=str[k++];
            j++;
        }
    }
    map<string,int>::iterator it,iq;
    map<string,bool>::iterator itt,ip;
    for(i=0; i<n; i++)
    {
        Max=0;
        for(it=m.begin(),itt=flag.begin(); it!=m.end(); it++,itt++)
        {
            if(!itt->second&&Max<it->second)
            {
                Max=it->second;
            }
        }
        if(Max==0) break;
        cnt=0;
        for(it=m.begin(),itt=flag.begin(); it!=m.end(); it++,itt++)
        {
            if(itt->second==false&&Max==it->second)
            {
                ans[cnt].as=it->first;
                ans[cnt++].ac=it->first.length();
                flag[it->first]=true;
            }
        }
        sort(ans,ans+cnt,cmp);
        cout<<Max<<endl;
        for(j=0; j<cnt-1; j++)
        {
            cout<<ans[j].as;
            if((j+1)%6==0) cout<<endl;
            else cout<<" ";
        }
        cout<<ans[j].as<<endl;
    }
    return 0;
}

策略二:

View Code
/*
  ID: dizzy_l1
  LANG: C++
  TASK: contact
*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdio>
#include<map>
#define MAXN 200010

using namespace std;

map<string,int>m;
map<string,bool>flag;
char s[15],str[MAXN],tstr[100];
struct ANS
{
    string as;
    int ac;
}ans[500];

bool cmp(ANS A,ANS B)
{
    if(A.ac<B.ac) return true;
    if(A.ac==B.ac&&A.as<B.as) return true;
    return false;
}

int main()
{
    freopen("contact.in","r",stdin);
    freopen("contact.out","w",stdout);
    int A,B,n,len,i,j,k,cnt,Max;
    string ts;
    scanf("%d%d%d",&A,&B,&n);
    while(scanf("%s",tstr)!=EOF) strcat(str,tstr);
    len=strlen(str);
    for(i=0; i<len; i++)//枚举所以的值映射到map中
    {
        j=0;
        k=i;
        ts="";
        while(j<A&&k<=len) ts+=str[k++],j++;//把ts的长度添加为A然后再映射
        while(j<=B&&k<=len)
        {
            flag[ts]=false;
            m[ts]++;
            ts+=str[k++];
            j++;
        }
    }
    map<string,int>::iterator it,iq;
    map<string,bool>::iterator itt,ip;
    for(i=0; i<n; i++)//扫描n次把前n大的依次输出
    {
        Max=0;
        for(it=m.begin(),itt=flag.begin(); it!=m.end(); it++,itt++)
        {
            if(!itt->second&&Max<it->second)
            {
                Max=it->second;
            }
        }
        if(Max==0) break;
        cnt=0;
        for(it=m.begin(),itt=flag.begin(); it!=m.end(); it++,itt++)
        {
            if(itt->second==false&&Max==it->second)
            {
                ans[cnt].as=it->first;
                ans[cnt++].ac=it->first.length();
                flag[it->first]=true;
            }
        }
        sort(ans,ans+cnt,cmp);
        cout<<Max<<endl;
        for(j=0; j<cnt-1; j++)
        {
            cout<<ans[j].as;
            if((j+1)%6==0) cout<<endl;
            else cout<<" ";
        }
        cout<<ans[j].as<<endl;
    }
    return 0;
}

转载于:https://www.cnblogs.com/zhourongqing/archive/2012/09/12/2682045.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值