您的位置:首页 > 理论基础 > 数据结构算法

poj 初级训练计划数据结构总结

2016-04-30 00:04 423 查看
两个下午一个晚上搞完了还是学到很多东西的。

poj 1035,3080,1936简单C语言题。3080可以KMP,但数据水可以枚举,KMP的话就是把第一个串的所有子串与下面几个串匹配难度也不大。

poj 2388 就是sort.

poj 2299 求逆序数==归并排序 当两个区间都排好时合并时你就可以跳跃性的直接求一个数和别的数有几个逆序而不是一个一个都比过来。这题可以当归并排序模板。

总体来说哈希容器字典树的运用更熟练了

#include<cstdio>
int a[600000],temp[600000],n;
long long sum;//结果可能很大
void mergeArray(int l,int r)//归并
{
int lStart = l,lEnd = (l+r)/2,
rStart = (l+r)/2+1,rEnd = r,
i1 = 0;
while(lStart<=lEnd&&rStart<=rEnd)
{
if(a[lStart]<=a[rStart])
{
temp[i1] = a[lStart];
lStart++;
i1++;
}
else
{
sum+=(long long)(lEnd-lStart+1);//求逆序数
temp[i1] = a[rStart];
rStart++;
i1++;
}
}
for(int i=lStart;i<=lEnd;i++)
{
temp[i1] = a[i];
i1++;
}
for(int i=rStart;i<=rEnd;i++)
{
temp[i1] = a[i];
i1++;
}
for(int i=l;i<=r;i++)
a[i] = temp[i-l];
}
void mergeSort(int l,int r)//二分
{
if(l<r)
{
mergeSort(l,(r+l)/2);
mergeSort((r+l)/2+1,r);
mergeArray(l,r);
}
}
int main()
{
while(scanf("%d",&n)&&n)
{
sum = 0;
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
mergeSort(0,n-1);
printf("%I64d\n",sum);
}
return 0;
}


poj 1611 并查集做的比较裸(路径压缩方法不正确先已知)

#include<cstdio>
#include<algorithm>
int n,m,l,fa[30005],am[30005],faGroup[30005];
void init()
{
for(int i=0;i<n;i++)
{
fa[i] = i;
am[i] = 1;
}
}
int toGetFarther(int x)
{
while(fa[x]!=x)
x = fa[x];
return x;
}
void unon()
{
int maam = -1,max = -1;
scanf("%d",&l);
for(int i=0;i<l;i++)
{
int s;
scanf("%d",&s);
faGroup[i] = toGetFarther(s);
}
for(int i=0;i<l;i++)
if(am[faGroup[i]]>maam){
maam = am[faGroup[i]];
max  = faGroup[i];
}
for(int i=0;i<l;i++)
{
if(faGroup[i]!=max){
fa[faGroup[i]]= max;
am[max]+=am[faGroup[i]];
}
}
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n+m==0)break;
init();
while(m--)
{
unon();
}
int ans = 1,re = toGetFarther(0);
for(int i=1;i<n;i++)
if(re==toGetFarther(i))ans++;
printf("%d\n",ans);
}
return 0;
}


poj 3349

每个雪花排个序哈希再排序,第一次处理哈希冲突问题方法太渣

#include<cstdio>
#include<algorithm>
#define ll long long
#define mod 2071723427
using namespace std;
struct node{
int am,ele[6];
}a[110000];
int n,w[6];
bool cmp(node no1,node no2)
{
return no1.am<no2.am;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<n;i++)
{
for(int j=0;j<6;j++)
scanf("%d",&w[j]);
sort(w,w+6);
for(int j=0;j<6;j++)
a[i].ele[j] = w[j];
a[i].am = 0;
for(int j=0;j<6;j++)
a[i].am = (a[i].am*10000777+a[i].ele[j])%mod;
}
sort(a,a+n,cmp);
bool sym =false;
for(int i=1;i<n;i++)
if(a[i].am==a[i-1].am)
{
int sum = 0;
for(int j=0;j<6;j++)
if(a[i].ele[j]==a[i-1].ele[j])sum++;
if(sum==6)
{
sym = true;
break;
}
}
if(!sym)printf("No two snowflakes are alike.\n");
else printf("Twin snowflakes found.\n");
}
return 0;
}


poj 3274

从第一个牛到第n个牛进行累加 记录每个i时的特征累加值也就是1-i(i>=1&&i<=n)时各个特征累加值。再以第一个特征值为基准求出每个s的各个特征的递增趋势。

当i跟j特征的递增趋势一样时那【i+1,j】这个区间个特征值相等。因为一个曲线每个点都往上平移一段相等长度时导数是不变的。

递增趋势是要哈希优化的(把n^2优化成n)

#include<cstdio>
#include<cstring>
#include<algorithm>
#define mod 197377
using namespace std;
int hash[200000][20],len[200000],n,k;
int a[110000][34];
int main()
{
while(scanf("%d%d",&n,&k)!=EOF)
{
int ans;
scanf("%d",&ans);
memset(len,0,sizeof(len));
for(int i=0;i<k;i++)
a[1][i] = (ans&(1<<i))/(1<<i);
for(int i=2;i<=n;i++)
{
scanf("%d",&ans);
for(int j=0;j<k;j++)
a[i][j] = a[i-1][j]+(ans&(1<<j))/(1<<j);
int w = a[i-1][0];
for(int j=0;j<k;j++)
a[i-1][j]-=w;
}
int w = a
[0];
for(int j=0;j<k;j++)
a
[j]-=w;
ans = 0;
len[0] = 1;
for(int i=1;i<=n;i++)
{
int pre = 0;
for(int j=0;j<k;j++)
pre = (pre*30+a[i][j]+mod)%mod;
for(int j=0;j<len[pre];j++)
{
int sum = 0;
for(int k1=0;k1<k;k1++)
if(a[hash[pre][j]][k1]==a[i][k1])sum++;
else break;
if(sum==k)
{
ans = max(ans,i-hash[pre][j]);
break;
}
}
hash[pre][len[pre]] = i;
len[pre]++;
}
printf("%d\n",ans);
}
return 0;
}


poj 1840 普通哈希

#include<cstdio>
#include<cstring>
#include<algorithm>
#define mod 12500000
using namespace std;
short mp[25000005];
int a,b,c,d,e,sum,am[105];
int main()
{
int i1 = 0;
for(int i=1;i<=50;i++)
{
am[i1] = i*i*i;
i1++;
am[i1] = -1*(i*i*i);
i1++;
}
while(scanf("%d%d%d%d%d",&a,&b,&c,&d,&e)!=EOF)
{
sum = 0;
memset(mp,0,sizeof(mp));
for(int i=0;i<i1;i++)
for(int j=0;j<i1;j++)
mp[am[i]*a+am[j]*b+mod]++;
for(int i=0;i<i1;i++)
for(int j=0;j<i1;j++)
for(int k=0;k<i1;k++)
if((am[i]*d+am[j]*e+am[k]*c)>=-12500000&&(am[i]*d+am[j]*e+am[k]*c)<=12500000)
sum+=mp[mod-1*(am[i]*d+am[j]*e+am[k]*c)];
printf("%d\n",sum);
}
return 0;
}


poj 2002 几何+哈希

1.把每个点的x和y轴坐标哈希

2.哈希处理冲突用邻接表比用链表更好快一倍

3.两个点(x1,y1),(x2,y2) 设x = x2-x1,y = y2-y1,则另外两个能够与这两个点组成正方形的点为(x1+y,y1-x)(x2+y,y2-x)或(x1-y,y1+x)(x2-y,y2+x);

#include<cstdio>
#include<cstring>
#define mul 27
#define mod 5013
int sum,n,l,x,y;
struct node{
int x,y;
}node[5025];
int next[5025],last[5025];
bool judge(int va,int x,int y)
{
int pre = last[va];
for(;pre!=-1;pre = next[pre])
if(node[pre].x==x&&node[pre].y==y)return true;
return false;
}
int main()
{
while(scanf("%d",&n)&&n)
{
sum = 0;
memset(next,-1,sizeof(next));
memset(last,-1,sizeof(last));
for(int i=0;i<n;i++)
{
scanf("%d%d",&x,&y);
int pre = ((x*mul+y)%mod+mod)%mod;
node[i].x = x;
node[i].y = y;
next[i] = last[pre];
last[pre] = i;
}
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
{
int x3,y3,x4,y4,x = node[i].x-node[j].x,y = node[i].y-node[j].y;
x3 = node[i].x+y,y3 = node[i].y-x;
x4 = node[j].x+y,y4 = node[j].y-x;
if(judge(((x3*mul+y3)%mod+mod)%mod,x3,y3)&&judge(((x4*mul+y4)%mod+mod)%mod,x4,y4))sum++;
x3 = node[i].x-y,y3 = node[i].y+x;
x4 = node[j].x-y,y4 = node[j].y+x;
if(judge(((x3*mul+y3)%mod+mod)%mod,x3,y3)&&judge(((x4*mul+y4)%mod+mod)%mod,x4,y4))sum++;
}
printf("%d\n",sum/4);
}
return 0;
}


poj 2503 map(红黑树哈希)

#include<cstdio>
#include<string>
#include<string.h>
#include<iostream>
#include<map>
using namespace std;
string a,b;
char str[30];
int main()
{
map<string,string>mp;
while(gets(str)&&str[0]!='\0')
{
int pre = 0;
a = b ="\0";
while(str[pre]!=' ')
pre++;
str[pre] = '\0';
a += str;
b += str+pre+1;
mp[b] = a;
}
while(cin>>a)
{
string b = mp[a];
if(b[0]!='\0')cout<<b<<endl;
else cout<<"eh"<<endl;
}
return 0;
}


poj 3253 哈夫曼+堆优化可以但我用的set

#include<cstdio>
#include<set>
#define ll long long
using namespace std;
int n;
int main()
{
scanf("%d",&n);
{
ll sum = 0;
multiset<ll>s;
for(int i=0;i<n;i++)
{
ll pre;
scanf("%I64d",&pre);
s.insert(pre);
}
for(int i=0;i<n-1;i++)
{
int pre = *s.begin();
s.erase(s.lower_bound(pre));
int pre2 = *s.begin();
s.erase(s.lower_bound(pre2));
sum+=(pre+pre2);
s.insert(pre+pre2);
}
s.clear();
printf("%I64d\n",sum);
}
return 0;
}


poj 2422

用堆维护n个最小值 o(n*n*logn) 不用的话直接枚举n个最小值o(n*n*n);

#include<cstdio>
#include<algorithm>
using namespace std;
int ans[2005],n,m,pre[2005],t,sum[2005];
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&m,&n);
for(int i=0;i<n;i++)
scanf("%d",&ans[i]);
m--;
while(m--)
{
sort(ans,ans+n);
for(int i=0;i<n;i++)
scanf("%d",&pre[i]);
sort(pre,pre+n);
for(int i=0;i<n;i++)
sum[i] = ans[i]+pre[0];
make_heap(sum,sum+n);
for(int i=1;i<n;i++)
for(int j=0;j<n;j++)
{
int temp = ans[j]+pre[i];
if(temp>=sum[0])break;
pop_heap(sum,sum+n);
sum[n-1] = temp;
push_heap(sum,sum+n);
}
for(int i=0;i<n;i++)
ans[i] = sum[i];
}
sort(ans,ans+n);
for(int i=0;i<n-1;i++)
printf("%d ",ans[i]);
printf("%d\n",ans[n-1]);
}
return 0;
}


poj 1442 堆优化

建两个堆 一个维护最小值(后几个大值的最小值)一个维护最大值(前几个最大值的最小值)

#include<cstdio>
#include<algorithm>
using namespace std;
int va[40000],heapMin[40000],heapMax[40000],n,m,lMin,lMax,k;
bool cmp(int a,int b)
{
return a>b;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
lMin = 0;
lMax = 0;
int all = 0;
for(int i=0;i<n;i++)
scanf("%d",&va[i]);
for(int i=0;i<m;i++)
{
int pre;
scanf("%d",&pre);
while(all<pre)
{
heapMin[lMin] = va[all];
all++;
lMin++;
push_heap(heapMin,heapMin+lMin,cmp);
if(lMax&&heapMin[0]<heapMax[0])
{
pop_heap(heapMin,heapMin+lMin,cmp);
pop_heap(heapMax,heapMax+lMax);
int t = heapMin[lMin-1];
heapMin[lMin-1] = heapMax[lMax-1];
heapMax[lMax-1] = t;
push_heap(heapMin,heapMin+lMin,cmp);
push_heap(heapMax,heapMax+lMax);
}
}
printf("%d\n",heapMin[0]);
heapMax[lMax] = heapMin[0];
lMax++;
push_heap(heapMax,heapMax+lMax);
pop_heap(heapMin,heapMin+lMin,cmp);
lMin--;
}
}
return 0;
}


poj 2513

1.字典树哈希 把每个单词都给个编号。

2.求欧拉路

(1)判断连通,并查集这题的路径压缩是正确的。

(2)每个点的度必须都为偶数或有两个是奇数,记录边数就行

#include<cstdio>
#include<string>
#include<iostream>
#include<cstring>
using namespace std;
int all[50005],pre = 0,fa[500005],ans[2],root[50005],id = 0;
string a,b;
class trieNode{
public:
int id;
trieNode *next[28];
trieNode()
{
id = -1;
memset(next,0,sizeof(next));
}
}*Root = new trieNode;
int insertTree(string a)
{
int l = a.size();
trieNode *p = Root;
for(int i=0;i<l;i++)
if(p->next[a[i]-'a']!=NULL) p = p->next[a[i]-'a'];
else{
trieNode *q = new trieNode;
p->next[a[i]-'a'] = q;
p = q;
}
if(p->id!=-1)return p->id;
else
{
p->id = id;
id++;
return id-1;
}
}
void init()
{
for(int i=0;i<=500001;i++)fa[i] = i;
}
int getFarther(int i)
{
if(i!=fa[i])fa[i] = getFarther(fa[i]);
return fa[i];
}
void unionFind(int x,int y)
{
int faX = getFarther(x);
int faY = getFarther(y);
fa[faY] = faX;
}
int main()
{
bool sym = false;
init();
int i1 = 0;
while(cin>>a>>b)
{
int x = insertTree(a);
int y = insertTree(b);
//printf("%d %d\n",x,y);
unionFind(x,y);
all[x]++;
all[y]++;
i1++;
}
for(int i=0;i<id;i++)
{
int j = i;
while(fa[j]!=j)j = fa[j];
root[j]++;
if(root[j]==id)sym = true;
}
if(sym)
{
for(int i=0;i<id;i++)
ans[all[i]%2]++;
if(!(ans[1]==2||ans[1]==0))sym = false;
}
if(sym||i1==0)printf("Possible\n");
else printf("Impossible\n");
return 0;
}


poj 2418 裸字典树 注意不止大小字母太坑

#include<cstdio>
#include<cstring>
char s[50];
int sum = 0;
class trieNode{
public:
int sum;
trieNode *next[130];
trieNode()
{
memset(next,0,sizeof(next));
sum = 0;
}
}*root = new trieNode;
void insertTrie(char s[])
{
trieNode *p = root;
int l = strlen(s);
for(int i=0;i<l;i++)
{
// printf("%d %c\n",i,s[i]);
if(p->next[s[i]]==NULL)
{
trieNode *q = new trieNode;
p->next[s[i]] = q;
p = p->next[s[i]];
}
else p = p->next[s[i]];
}
(p->sum)++;
}
void dfs(trieNode *p,char s[],int l)
{
if(p->sum){
s[l] = '\0';
printf("%s %.4f\n",s,(double)(p->sum)/sum*100.0);
}
for(int i=0;i<=129;i++)
{
if(p->next[i]!=NULL)
{
//printf("%c\n",i);
s[l] = i;
dfs(p->next[i],s,l+1);
}
}
}
int main()
{
sum = 0;
while(gets(s)!=NULL)
{
sum++;
insertTrie(s);
}
if(sum==0)return 0;
dfs(root,s,0);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: