ACM Steps_Chapter Five_Section2

统计难题

/*
即每个结点有多个儿子结点。。。然后单词的前缀会在树中重合,
而结点的数据域随题目而变,例如这题,数据域prefixNum表示含以该结点结尾的前缀的单词的个数。
那么如果你想知道树中某单词是否存在,则数据域isWord == 1表示存在以该结点结尾的单词
 
字典树效率高在于他只需要遍历该单词
*/
#include <iostream>
using namespace std;

struct Node
{
    struct Node *child[26];
    int perfixNum;//表示含以该结点结尾的前缀的单词的个数
};

Node *root;

void Init()//初始化
{
    root = new Node;
    for (int i = 0; i < 26; i++)
    {
        root->child[i] = NULL;
    }
}

//插入
void Insert(char word[])
{
    int len = strlen(word);
    Node *pNode = root;
    for (int i = 0; i < len; i++)
    {
        if (pNode->child[word[i] - 'a'] == NULL)
        {
            //不存在该结点,则创建一个
            Node *newNode = new Node;
            newNode->perfixNum = 1;
            for (int j = 0; j < 26; j++)
            {
                newNode->child[j] = NULL;
            }

            pNode->child[word[i] - 'a'] = newNode;
        }
        else
        {
            pNode->child[word[i] - 'a']->perfixNum++;
        }
        
        pNode = pNode->child[word[i] - 'a'];
    }
}

//查找,通过遍历该单词到该单词的结尾结点的prefixNum就是答案了
int Find(char word[])
{
    int len = strlen(word);
    Node *pNode = root;
    int i;
    for (i = 0; i < len; i++)
    {
        if (pNode->child[word[i] - 'a'] != NULL)
        {
            pNode = pNode->child[word[i] - 'a'];
        }
        else
        {
            break;
        }
    }

    if (i == len)
    {
        return pNode->perfixNum;
    }
    else
    {
        return 0;
    }
}

int main()
{

    char word[15], prefixWord[15];
    Init();
    while (gets(word), word[0] != 0)
    {
        Insert(word);
    }

    while (gets(prefixWord) != NULL)
    {
        printf("%d\n", Find(prefixWord));
    }
    return 0;
}

Phone List

// Trie 基础模板
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <stack>
#include <iostream>
#define Max 100000
#define sigma_size 10
using namespace std;
int ch[Max][sigma_size];
bool val[Max];
int cnt;
char str[10002];
int idx(char c)
{
    return  c-'0';
}
bool insert(char *s)
{
    int i,n=strlen(s);
    int c,u=0;
    for(i=0;i<n;i++)
    {
        c=idx(s[i]);
        if(!ch[u][c])
        {
          memset(ch[cnt],0,sizeof(ch[cnt]));
          val[cnt]=false;
          ch[u][c]=cnt++;

        }
        if(val[u]) return false;
        u=ch[u][c];
    }
    val[u]=true;
    for(i=0;i<sigma_size;i++) //做题时开始忘记这、错了下
    if(ch[u][i]) return false;
    return true;
}
int main()
{
    int T;
    int n,i;
    scanf("%d",&T);
    bool flag;
    while(T--)
    {
        flag=true;
        val[0]=0;
        memset(ch[0],0,sizeof(ch[0]));
        cnt=1;
        scanf("%d",&n);
        for(i=0;i<n;i++)
        {
            scanf("%s",str);
            if(!insert(str))
             flag=false;
        }
        if(flag)
           printf("YES\n");
        else
           printf("NO\n");
    }
    return 0;
}

Flying to the Mars

/*
题目大意:
给你一堆士兵的等级,等级高的的士兵可以当等级小的士兵的师傅,
一个士兵最多一个师傅(可以没有),一个师傅最多1个徒弟(可以没有),如果是师徒关系,
可以用一把扫帚练习技能,问你如果全部士兵都用过扫帚练习时最小需要的扫帚数量。
解题思路:
实质就是字典树的应用。如果所有士兵等级都不同,则就可以用一条师徒链,
所以就需要一把扫帚,而如果出现2个相同等级的士兵,则需要开辟另外一条师徒链,
以此类推,发现只要求出等级相同的最多士兵数,就需要多少把扫帚。
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct Trie
{
    int cnt;
    Trie *child[10];
    Trie(){cnt=0;memset(child,NULL,sizeof(child));}
}*root;
int ans;
void insert(char *s)
{
    int id;
    Trie *p=root;
    for(int i=0;s[i];)
    {
        id=s[i]-'0';
        if(!p->child[id])
           p->child[id]=new Trie();
        p=p->child[id];
        ++i;
    }
    p->cnt++;
    ans=max(ans,p->cnt);
}
int main()
{
    char s[35];
    int n,pos;
    for(;~scanf("%d",&n);)
    {
        ans=0;
        root=new Trie();
        for(int i=0;i<n;++i)
        {
            scanf("%s",s);
            pos=0;
            for(;s[pos]=='0';++pos);
            insert(s+pos);
        }
        printf("%d\n",ans);
    }
    return 0;
}

魔咒词典

#include<cstdio>
#include<algorithm>

using namespace std;

char str[130];//数据读入所用 
char moz[101000][30];//魔咒 
char func[101000][90];//对应功能 
char Result[130];//结果 
int val[101000];//对魔咒排序所用
int vafun[101000];//对功能排序所用 
int tot=0;//魔咒总个数 

bool cmp(int a,int b){//快排魔咒(从小到大,可也以从大到小,看自己喜欢)
	if(strcmp(moz[a],moz[b])==-1) return true;
	return false;
}//可以直接写成return strcmp(moz[a],moz[b])==-1;

bool _cmp(int a,int b){//对功能排序 
	if(strcmp(func[a],func[b])==-1) return true;
	return false;
}//return strcmp(func[a],func[b])==-1;

bool Finda(char *s){//二分查找魔咒 
	int left=0,right=tot-1,mid;
	while(left<=right){
		mid=(left+right)>>1;//mid=(left+right)/2; 
		if(!strcmp(moz[val[mid]],s)){
			strcpy(Result,func[val[mid]]);//把功能复制给结果Result 
			return true;//返回 
		}else if(strcmp(moz[val[mid]],s)==1){
			right=mid-1;
		}else left=mid+1;
	}
	return false;
}

bool Findb(char *s){//十分查找功能 
	int left=0,right=tot-1,mid;
	while(left<=right){
		mid=(left+right)>>1;
		if(!strcmp(func[vafun[mid]],s)){
			strcpy(Result,moz[vafun[mid]]+1);
			int len=strlen(moz[vafun[mid]]);
			Result[len-2]='\0';
			return true;
		}else if(strcmp(func[vafun[mid]],s)==1){
			right=mid-1;
		}else left=mid+1;
	}
	return false;
}

int main(){
	int i,Q,len;
	bool flag;
	while(gets(str),str[0]!='@'){
		len=strlen(str);
		for(i=0;str[i];i++){//存入魔咒 
			moz[tot][i]=str[i];
			if(str[i]==']') break;
		}
		moz[tot][++i]='\0';
		val[tot]=tot;
		strcpy(func[tot],str+i+1);//存入功能 
		func[tot][len-i-1]='\0';
		vafun[tot]=tot++;
	}
	sort(val,val+tot,cmp);
	sort(vafun,vafun+tot,_cmp);
	scanf("%d",&Q);
	getchar();
	while(Q--){
		gets(str);
		if(str[0]=='['){
			flag=Finda(str);
			if(flag==false) puts("what?");
			else puts(Result);
		}else{
			flag=Findb(str);
			if(flag==false) puts("what?");
			else puts(Result);
		}
		memset(Result,0,sizeof(Result));
	}
	return 0;
}

确定比赛名次

/*
简单拓扑排序问题,问题在于选取入度为零的点。
*/
#include <stdio.h>
#define MAX 505
#include <string.h>
 
int map[MAX][MAX], N, M, hash[MAX];
 
void update( int x )
{
    for( int i= 1; i<= N; ++i )
    {
        map[x][i]= 0;
    }
 
}
 
void Tsort(  )
{
    for( int i= 1; i<= N; ++i )
    {
        for( int j= 1; j<= N; ++j )
        {
            if( hash[j] )
            {
                continue;
            }
            int sign= 1;
            for( int k= 1; k<= N&& sign; ++k )
            {
                if( map[k][j] )
                {
                    sign= 0;
                    break;
                }
            }
            if( sign )
            {
                printf( i== 1? "%d": " %d", j );
                hash[j]= 1;
                update( j );
                break;
            }
        }
    }
    puts( "" );
}
 
int main(  )
{
    while( scanf( "%d%d", &N, &M )!= EOF )
    {
        memset( map, 0, sizeof( map ) );
        memset( hash, 0, sizeof( hash ) );
        for( int i= 1; i<= M; ++i )
        {
            int x, y;
            scanf( "%d%d", &x, &y );
            map[x][y]= 1;
        }
        Tsort(  );
    }
    return 0;
}

产生冠军

#include <stdio.h>
#include <string.h>

#define MAXN 1005

int n, top_name, indegree[MAXN];
char name[MAXN][15];

void Init(){
    top_name = 0;
    memset(indegree, 0, sizeof(indegree));
}

int find_str(char *s){
    int i;
    for(i=0; i<top_name; i++){
        if(strcmp(name[i], s) == 0) break;
    }
    if(i==top_name){
        strcpy(name[top_name++], s);
    }
    return i;
}

int main(){
    int i, k, cnt, pos1, pos2;
    char s1[15], s2[15];

    while(scanf("%d", &n) == 1 && n){
        Init();
        for(i=0; i<n; i++){
            scanf("%s %s", s1, s2);
            pos1 = find_str(s1), pos2 = find_str(s2);
            indegree[pos2]++;
        }

        cnt = 0;
        for(i=0; i<top_name; i++){
            if(indegree[i] == 0){k = i; cnt++;}
            if(cnt > 1) break;
        }

        if(cnt == 1) printf("Yes\n");
        else printf("No\n");
    }

    return 0;
}

Box Relations

/*
把一个箱子分成三个面,即X,Y,Z
拿X来说,把这个面分为上下两部分,上面记为1,下面记为1+n,当读入X A B条件的时候,
那么A箱的下表面和B箱的上表面构成关系,虽然题目中说是A要比B小,
但是由于我们最后记录的时候i是从小到大来的,所以我们把A放在B的上面,结果是A的坐标比B小
 
当读入I A B的时候,那么A箱的上表面大于B箱的下表面,B箱的上表面要大于A箱的下表面,
在纸上画个图就很好理解了,接下来就是分成X,Y,Z三个面分别拓扑就好
*/

 #include <cstdio>
 #include <cstring>
 using namespace std;
 
 const int N=2010;
 bool g[3][N][N];
 int ind[3][N],n;
 int topo[3][N];
 int x[N],y[N],z[N];
 bool toposort(int k)
 {
     memset(ind[k],0,sizeof(ind[k]));
     for(int v=1;v<=n;v++)
         for(int u=1;u<=n;u++)
             if(g[k][u][v]) ind[k][v]++;
     for(int i=0;i<n;i++)
     {
         int u;
         for(u=1;u<=n;u++)
             if(ind[k][u]==0) break;
         if(u>n) return false;
         topo[k][i]=u; ind[k][u]--;
         for(int v=1;v<=n;v++)
             if(g[k][u][v]) ind[k][v]--;
     }
     return true;
 }
 int main()
 {
     int m,C=0;
     while(scanf("%d%d",&n,&m),n||m)
     {
         memset(g,0,sizeof(g));
         for(int i=0;i<3;i++)
             for(int u=1;u<=n;u++) g[i][u][u+n]=1;
         while(m--)
         {
             char op[2];
             int u,v;
             scanf("%s%d%d",op,&u,&v);
             if(op[0]=='I')
             {
                 for(int i=0;i<3;i++)
                     g[i][v][u+n]=g[i][u][v+n]=1;
             }
             else
             {
                 int k=op[0]-'X';
                 g[k][u+n][v]=1;
             }
         }
         n*=2;
         bool flag=true;
         for(int i=0;flag&&i<3;i++)
             if(!toposort(i)) flag=false;
         n/=2;
         if(flag)
         {
             printf("Case %d: POSSIBLE\n",++C);
             for(int i=0;i<2*n;i++)
                 x[topo[0][i]]=y[topo[1][i]]=z[topo[2][i]]=i;
             for(int i=1;i<=n;i++)
                 printf("%d %d %d %d %d %d\n",x[i],y[i],z[i],x[i+n],y[i+n],z[i+n]);
         }
         else printf("Case %d: IMPOSSIBLE\n",++C);
         printf("\n");
     }
     return 0;
 }

Entropy

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <queue>
using namespace std;

const int MAXN = 1010;

struct node
{
    int data;
    int dep;
    node *L, *R;
    node()
    {
        data = 0;
        dep = 0;
        L = NULL;
        R = NULL;
    }
    bool operator <(node a) const
    {
        return a.data < data;
    } //重载小于号 
};

int ans;
char str[MAXN];
int huf[MAXN];

priority_queue<node> Q;

void BuildHuffman()
{
    node *p, *q, *T;
    while(Q.size() != 1)
    {
        p = new node();
        q = new node();
        T = new node();
        *p = Q.top(); Q.pop();
        *q = Q.top(); Q.pop();
        T->data = p->data + q->data;
        T->L = p, T->R = q;
        Q.push(*T);
    }
    return ;
}

queue<node> q;

void solve()
{
    node root;
    root = Q.top(); Q.pop();
    root.dep = 0;
    q.push(root);
    while(!q.empty())
    {
        node x = q.front(); q.pop();
        if(x.L)
        {
            x.L->dep = x.dep + 1;
            q.push(*(x.L));
        }
        if(x.R)
        {
            x.R->dep = x.dep + 1;
            q.push(*(x.R));
        }
        if(!x.L && !x.R)
        {
            ans += x.dep * x.data;
        }
    }
}

/*void dfs(node *p, int dep)
{
    if(!p->L && !p->R)
    {
        ans += p->data * dep;
    }
    if(p->L)
    {
        dfs(p->L, dep+1);
    }
    if(p->R)
    {
        dfs(p->R, dep+1);
    }
}*/

void init()
{
    ans = 0;
    while(!Q.empty()) Q.pop();
    while(!q.empty()) q.pop();
    memset(huf, 0, sizeof(huf));
}

int main()
{
    while(scanf("%s", str) && strcmp(str, "END"))
    {
        init();
        int len = strlen(str);
        for(int i = 0; str[i]; i++)
        {
            huf[str[i]]++;
        }
        for(int i = 0; i < 100; i++) if(huf[i])
        {
            node t;
            t.data = huf[i];
            Q.push(t);
        }
        if(Q.size() == 1) //特判
        {
            printf("%d %d 8.0\n", len*8, len);
            continue;
        }
        BuildHuffman();
        solve();
        //dfs(root, 0); 用DFS也可以实现 
        printf("%d %d %.1lf\n", len*8, ans, len*8.0/ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值