09-08 HDU_Steps5.2 字典树,拓扑,哈夫曼 HDU1075 HDU1251 HDU1671 HDU1285 HDU2094 HDU3231 HDU1053 HDU2527

5.2.1 HDU1075 What Are You Talking About

简单的字典树,在翻译时注意一点小问题,字符串的问题就是处理有些麻烦..

#include <cstdio>
#include <string.h>
#include <cstdlib>
using namespace std;
char line[30],s1[12],s2[12],tline[3010];
struct trie{
	trie *next[26];char c[12];int has;	
	trie(){for(int i=0;i<26;i++)next[i]=NULL;has=0;}
}*root;
void instrie(char s11[12],char s12[12]){
	int len=strlen(s12);
	trie *p=root;
	for(int i=0;i<len;i++){
		int t=s12[i]-'a';
		if(p->next[t]==NULL)p->next[t]=new trie;
		p=p->next[t];	
	} 	
	p->has=1;
	strcpy(p->c,s11);
}
bool search(char s11[12]){
	int len=strlen(s11);
	trie *p=root;
	for(int i=0;i<len;i++){
		int t=s11[i]-'a';
		if(p->next[t]==NULL)return false;
		p=p->next[t];	
	} 	
	if(p->has==0)return false;
	strcpy(s2,p->c);
	return true;
}
int main(){
	root=new trie;
	while(gets(line)){
		if(strcmp(line,"START")==0)continue;
		if(strcmp(line,"END")==0)break;
		sscanf(line,"%s%s",s1,s2);
		instrie(s1,s2);	
	}	
	while(gets(tline)){
		if(strcmp(tline,"START")==0)continue;
		if(strcmp(tline,"END")==0)break;
		int i=0,j=0,len=strlen(tline);	
		while(i<len){
			if(tline[i]<'a'||tline[i]>'z'){
				//查找这个单词,找到输出对应的单词,找不到直接输出原文 
				s1[j]='\0';
				if(search(s1))printf("%s",s2);
				else printf("%s",s1);
				//打印标点,开始搜索下一个单词 
				printf("%c",tline[i]);
				j=0,i++;
			}else{
				s1[j]=tline[i];
				i++,j++;
			}
		}
		printf("\n");
	}	
}


5.2.2 HDU1251 统计难题

字典树,经过的字母标记全部加一,查找的时候返回该字母的标记


5.2.3 HDU1671 Phone List

判断一组字符串,有没有字符串是其它字符串的前缀

读入的时候就可以判断该字符串是不是其它字符串的前缀,或者后缀..用一个标记标记该位置是否为单词结尾

如果存入单词的结尾处已经有单词经过,说明存入单词是另一单词的前缀,如果存入单词经过的地方有其它单词的结尾,说明另一单词是存入单词的前缀..这两种情况都返回false

int instrie(char s1[11]){
	int len=strlen(s1);
	int r=1; 
	trie *p=root;
	for(int i=0;i<len;i++){
		int t=s1[i]-'0';
		//是其它单词的前缀 
		if(i==len-1&&p->next[t]!=NULL)r=0;
		if(p->next[t]==NULL)p->next[t]=new trie;	
		p=p->next[t];
		//其它单词是它的前缀
		if(p->e==1)r=0; 
	}	
	p->e=1;//标记在这里结束 
	return r; 
}

5.2.4 HDU1285 确定比赛名次

输入数据保证有序,那就是赤果果的拓扑排序了

输入有点阴,会有重复边,注意不要把入度算多了!

#include <cstdio>
#include <string.h>
using namespace std;
const int MAXN=505;
int map[MAXN][MAXN],n,m,a,b,in[MAXN],ans[MAXN];
void topo(){
	int top=1,u;
	memset(ans,0,sizeof ans);
	while(1){
		for(u=1;u<=n;u++)if(in[u]==0)break;
		if(u==n+1)return;
		in[u]=-1;
		ans[top++]=u;
		for(int v=1;v<=n;v++)if(map[u][v]==1)in[v]--;
	}
}
int main(){
	while(scanf("%d%d",&n,&m)!=EOF){
		memset(map,0,sizeof map);
		memset(in,0,sizeof in);
		
		while(m--){
			scanf("%d%d",&a,&b);
			if(map[a][b]==0)map[a][b]=1,in[b]++;
		}	
		
		topo();
		
		printf("%d",ans[1]);
		for(int i=2;i<=n;i++)printf(" %d",ans[i]);
		printf("\n");
	}
	return 0;	
} 

5.2.5 HDU2094 产生冠军

首先转换字符串为标号,然后建图

冠军存在的条件是,有且仅有一个入度为0的点并且这个从这个点可以访问到其它所有点


5.2.6 HDU3231 Box Relations

一道好题,但是不会做...建图比较难,三个轴都要建图,然后分别拓扑排序,排序失败的话就说明impossible了..

代码不是我自己写的,基本都是模仿大牛的代码的..

#include <cstdio>
#include <string.h>
using namespace std;
int n,r,a,b,ne;
char c;
struct node{int v,next;node(){};node(int a,int b){next=a,v=b;}}e[500000];
int head[4][2001],ind[4][2001],ans[4][2001],q[4][2001];
//邻接表建图 
void ins(int op,int u,int v){
	e[ne]=node(head[op][u],v);
	head[op][u]=ne++; 
	ind[op][v]++; 
}
//初始化,注意初始化每个立方体本身边的关系 
void init(){
	ne=0;
	memset(ind,0,sizeof ind);
	memset(head,-1,sizeof head);
	for(int i=1;i<=n;i++)for(int j=1;j<=3;j++)ins(j,i,i+n);		
}
//拓扑排序,返回是否成功 
bool topo(int op){
	int front=0,top=0;
	for(int i=1;i<=2*n;i++)
		if(ind[op][i]==0)q[op][top++]=i,ind[op][i]--;
	while(front<top){
		int u=q[op][front++];
		for(int i=head[op][u];i!=-1;i=e[i].next){
			int v=e[i].v;
			ind[op][v]--; 
			if(ind[op][v]==0)q[op][top++]=v,ind[op][v]--;
		}	
	} 
	return top==2*n;
}
void solve(){
	for(int i=1;i<=3;i++){
		if(!topo(i)){printf("IMPOSSIBLE\n");return;}	
	}
	printf("POSSIBLE\n");
	//根据拓扑关系决定答案 
	for(int k=1;k<=3;k++)for(int i=0;i<2*n;i++)ans[k][q[k][i]]=i;
	for(int i=1;i<=n;i++){
		printf("%d %d %d ",ans[1][i],ans[2][i],ans[3][i]);
		printf("%d %d %d\n",ans[1][i+n],ans[2][i+n],ans[3][i+n]);	
	}
}
int main(){
	int cas=1;
	while(scanf("%d%d",&n,&r),n||r){
		init();
		while(r--){
			scanf(" %c%d%d",&c,&a,&b);
			if(c=='I'){
				for(int i=1;i<=3;i++){
					ins(i,a,b+n);
					ins(i,b,a+n);	
				}
			}else{
				ins(c-'X'+1,a+n,b);	
			}
		}
		printf("Case %d: ",cas++);
		solve();
		printf("\n");
	}
}


5.2.7 HDU1053 Entropy

描述一大敌,其实就是Huffman编码,用优先队列实现,注意只有一种字符的情况

#include <cstdio>
#include <queue>
#include <string.h>
using namespace std;
char line[10000];
int pl[27],len;
int main(){
	while(scanf("%s",line)){
		if(strcmp(line,"END")==0)break;
		
		//统计频度 
		memset(pl,0,sizeof pl);
		len=strlen(line);
		for(int i=0;i<len;i++){
			if(line[i]=='_')pl[0]++;
			else pl[line[i]-'A'+1]++;
		}
		//判断是否单一字符
		int yes=0; 
		for(int i=0;i<27;i++){
			if(pl[i]==len){
				printf("%d %d 8.0\n",len*8,len);
				yes=1;
				break;	
			}	
		}
		if(yes)continue;
		
		//使用优先队列统计HUFFMAN编码 
		priority_queue<int,vector<int>,greater<int> > q;
		int ans=0,a,b;
		for(int i=0;i<27;i++)if(pl[i]!=0)q.push(pl[i]);
		while(1){
			int a=q.top();q.pop();
			if(q.empty())break;
			int b=q.top();q.pop();
			ans+=a+b;
			q.push(a+b);
		}			
		printf("%d %d %.1lf\n",len*8,ans,len*8.0/ans);
	}	
	return 0;	
}

5.2.8 HDU2527 Safe Or Unsafe

也是Huffman编码 代码和上面差不多





你可能感兴趣的:(c,struct,list,null,search)