posts - 21,  comments - 9,  trackbacks - 0
 

给出一棵二分搜索树,再给一个节点编号n,求以这个节点为根节点的子树叶子节点的最大值与最小值。若n是奇数,那么他必然是个叶子节点,最大最小都是他自己。否则求n所在的层数,他的层数就是他的因子中2的个数(规律),转化为求n的因子中2的个数。而2的个数取决于n的二进制表示中最后一个1所处的位置i,因为之前的某几个1,假设处于j(j>i),那么n可以表示为2^j+2^i+2^x(x>i且个数未定)=2^i*(1+2^(j-i)+2^(x-i)),看见米有,n必须有i个因子2.求出i的值后,即层数,可得n的左右各有num=2^i-1个儿孙(女),不信请看图,概不解释。那么最小值就是n-num,最大值就是n+num.那马怎么求num呢,这时就可以请出神奇的位运算了(以速度"嗖嗖嗖"的快而扬名ACM界),首先是确定二进制n后缀连续0的个数,这样想:怎么取出这i个0呢?其实不必考虑这个掣肘的问题,咱们直接跑到结果上考虑,就是求2^i-1,你花仙米有,这是个等差数列的前n项和:2^0+2^1+2^2+……+2^(i-1).那么这又是个什么形式呢,这就是二进制只有连续i个1的(其余都是前导0)数的十进制表示形式,OK,好办了,利用系统自动转换功能,咱们只需把这i个1罗列出来即可:把n的后i个0变成1,可采取如下形式n^(n|n-1),稍微解释下,n|n-1是将后i个0变成1,把第i+1个1变成0,然后和n抑或一下,得到什么?哈,就是2^i-1,即i个1的十进制形式,代码就不放了,上面明白了实现很简单的!
那啥,转载务必注明:Pzjay原创呃!

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/shifuwawa/archive/2010/01/07/5153446.aspx

以下是我根据上面的描述写出来的代码,一次AC,0MS
#include<iostream>
using namespace std;
int main()
{
 int n;
 cin>>n;
 while(n--)
 {
  int k;
  cin>>k;
  if(k%2!=0)
  {
   cout<<k<<" "<<k<<endl;
   continue;
  }
  int num=k^(k|k-1);
  cout<<k-num<<" "<<k+num<<endl;
 }
 return 0;
}

posted @ 2010-08-19 13:13 崔佳星 阅读(1081) | 评论 (0)编辑 收藏
不得不说poj 2305是一道进制转换的经典题目。一开始我没有考虑到整除的情况。所以总是WA。后来加了一个判断就AC了。
#include<iostream>
#include<cstring>
using namespace std;
char s1[1005],s2[15];
int main()
{
 int n;
 while(cin>>n&&n)
 {
  cin>>s1>>s2;
  __int64 a=0,b=0;int len1,len2;
  len1=strlen(s1);len2=strlen(s2);
  for(int i=0;i<len2;i++)
  {
   a*=n;
   a+=s2[i]-'0';
  }
  for(int j=0;j<len1;j++)
  {
   b*=n;
   b+=s1[j]-'0';
   if(b>=a)
    b%=a;
  }
  int k=0;
  if(b==0)
  {
   cout<<"0"<<endl;
   continue;
  }
  while(b!=0)
  {
   s2[k++]=b%n+'0';
   b/=n;
  }
  s2[k]='\0';
  int len=strlen(s2);
  for(k=len-1;k>=0;k--)
   cout<<s2[k];
  cout<<endl;
 }
 return 0;
}
posted @ 2010-08-19 11:26 崔佳星 阅读(1138) | 评论 (0)编辑 收藏
这应该是一道DP题。下面的代码是我见过的最短的代码。拿出来跟大家分享。
#include<iostream>
#include<stdio.h>
using namespace std;
#define max(a,b) ((a)>(b)?(a):(b))
int arrival[1450];
int trip[1450];
int time[1450];
int n,t,m;
int main()
{
 int test;
 cin>>test;
 while(test--)
 {
  cin>>n>>t>>m;
  for(int i=1;i<=m;i++)
   scanf("%d",arrival+i);
  trip[0]=time[0]=0;
  for(int j=1;j<=m;j++)
  {
   time[j]=max(time[max(j-n,0)],arrival[j])+2*t;
   trip[j]=trip[max(j-n,0)]+1;
  }
  printf("%d %d\n",time[m]-t,trip[m]);
 }
 return 0;
}


然后是该作者的介绍

题目大意:有一些汽车在左岸,你要用一条小破船把它们拉到右岸去。每个测试点包含多个测试数据。第一行的整数C表示测试数据的数目。接下来每个测试数据的第一行为三个整数N, T, M表示一次可以运送N辆汽车,到达对岸的时间为T,汽车的总数是M。接下来的M行每行有一个整数,表示这辆汽车什么时候会来到左岸。对于每个测试数据,输出两个整数,分别是最少要耗用多少时间(包括你等车的时间,就是从0开始直到最后一辆车到达右岸),以及在这个前提下你最少要运送多少次。只要到右岸去就算作一次。

这个题出在DP专场不太合适……事实上本人用贪心的手段就解决了这个问题。

贪心策略:先运送M % N辆汽车到对岸(就是M除上N的余数),之后每次运N辆汽车,直到运完为止。这里的意思是,只有船上确实有了这么多车才出发,在此之前等着那些车来。对于这个策略的证明各位可以使用数学归纳法,比较简单,这里就不耗费篇幅了。

posted @ 2010-08-18 21:18 崔佳星 阅读(1151) | 评论 (0)编辑 收藏

DFS题目啊。看通过率就知道非常简单的。一下付代码,大家自己看下。
#include<iostream>
using namespace std;
char array[100][100];
int n,m;int count=0;
void dfs(int i,int j)
{
 if(i<0||i>n||j<0||j>m)
  return ;
 if(array[i][j]!='W')
  return ;
 array[i][j]='.';
 dfs(i-1,j);dfs(i+1,j);dfs(i,j-1);dfs(i,j+1);dfs(i-1,j-1);dfs(i-1,j+1);dfs(i+1,j-1);dfs(i+1,j+1);
}
void check()
{
 int i,j;
 for(i=0;i<n;i++)
 {
  for(j=0;j<m;j++)
  {
   if(array[i][j]=='W')
   {
    dfs(i,j);
    count++;
   }
  }
 }

}
int main()
{
 cin>>n>>m;
 for( int i=0;i<n;i++)
 {
  for(int j=0;j<m;j++)
  {
   cin>>array[i][j];
  }
 }
 check();
 cout<<count<<endl;
 return 0;
}

posted @ 2010-08-18 19:20 崔佳星 阅读(1231) | 评论 (0)编辑 收藏
这道题目视枚举题。直接枚举各个长度,然后求最小面积即可。
#include<iostream>
using namespace std;
int main()
{
 int test;
 cin>>test;
 while(test--)
 {
  int n;
  cin>>n;
  int min=100000000;
  int area;
  int k;
  for(int i=1;i<=n;i++)
  {
   for(int j=1;i*j<=n;j++)
   {
    if(n%(i*j)==0)
    {
     k=n/(i*j);
     area=i*j+i*k+j*k;
     if(area<min)
      min=area;
    }
   }
  }
  cout<<min*2<<endl;
 }
 return 0;
}
posted @ 2010-08-18 17:01 崔佳星 阅读(249) | 评论 (0)编辑 收藏

这是一道模拟题。说白了就是石头剪子布的问题。此题的关键点是要开两个数组。一个是原来的。一个是改动后的,每次改动完之后都要用改动之后的初始化原来的一次。下面请看代码。我把函数分的比较详细。便于大家阅读。
#include<iostream>
using namespace std;
char array[102][102];
char temp[102][102];
int r,c,n;
void init()
{
 int i,j;
 for( i=1;i<=r;i++)
  {
   for( j=1;j<=c;j++)
   {
    array[i][j]=temp[i][j];
   }
  }
}
void change(int i,int j)
{
 if(array[i][j]=='R')
 {
  if(i>1&&array[i-1][j]=='S')
   temp[i-1][j]='R';
  if(i+1<=r&&array[i+1][j]=='S')
   temp[i+1][j]='R';
  if(j>1&&array[i][j-1]=='S')
    temp[i][j-1]='R';
  if(j+1<=c&&array[i][j+1]=='S')
    temp[i][j+1]='R';
 }
 else
  if(array[i][j]=='P')
 {
  if(i>1&&array[i-1][j]=='R')
   temp[i-1][j]='P';
  if(i+1<=r&&array[i+1][j]=='R')
    temp[i+1][j]='P';
  if(j>1&&array[i][j-1]=='R')
    temp[i][j-1]='P';
  if(j+1<=c&&array[i][j+1]=='R')
    temp[i][j+1]='P';
 }
 else
  if(array[i][j]=='S')
 {
  if(i>1&&array[i-1][j]=='P')
   temp[i-1][j]='S';
  if(i+1<=r&&array[i+1][j]=='P')
    temp[i+1][j]='S';
  if(j>1&&array[i][j-1]=='P')
    temp[i][j-1]='S';
  if(j+1<=c&&array[i][j+1]=='P')
    temp[i][j+1]='S';
 }
}
void occupy()
{
 int i,j;
 while(n--)
 {
  for(i=1;i<=r;i++)
   {
    for(j=1;j<=c;j++)
    {
     change(i,j);     
    }
   }
  init();
 }

}
int main()
{
 int test;
 cin>>test;
 int i,j;
 while(test--)
 {
  cin>>r>>c>>n;
  for( i=1;i<=r;i++)
  {
   for( j=1;j<=c;j++)
   {
    cin>>array[i][j];
    temp[i][j]=array[i][j];
   }
  }
  /////////////OK 输入字符完毕。
  occupy();
  for( i=1;i<=r;i++)
  {
   for( j=1;j<=c;j++)
   {
    cout<<array[i][j];
   }
   cout<<endl;
  }
  if(test!=0)
   cout<<endl;
 }
 return 0;
}

posted @ 2010-08-18 16:13 崔佳星 阅读(1009) | 评论 (0)编辑 收藏
这个题首先要把输入的坐标转化成邻接矩阵的形式。之后再利用邻接矩阵使用普里姆算法计算最小生成树。并对其中的边进行排序。找出减去S个较大的后最大的那一个。因为较大的那几个可以用卫星传输
#include<iostream>
#include<cmath>
#include<algorithm>
#include<stdio.h>
using namespace std;
typedef struct
{
 double x;
 double y;
}point;
point array[505];
double len[505][505];
double kk[505],next[505];
double re[505];
int sa,num;
double dis(point first,point second)
{
 return sqrt((first.x-second.x)*(first.x-second.x)+(first.y-second.y)*(first.y-second.y));
}
void prim(int n)
{
 int i,j;
  //////////读入数据完毕。开始构建邻接矩阵
  for(i=0;i<num;i++)
  {
   for(j=0;j<num;j++)
   {
    len[i][j]=15000000;
   }
  }
  for(i=0;i<num;i++)
  {
   for(j=0;j<num;j++)
   {
    if(i!=j)
     len[i][j]=dis(array[i],array[j]);
   }
  }
  for(i=0;i<num;i++)
  {
   kk[i]=len[0][i];
   next[i]=0;
  }
  /////////邻接矩阵构建完毕
  int count=0;i=0;
  while(count<num-1)
  {
   if(next[i]!=-1)
   {
    for(j=0;j<num;j++)
    {
     if(i!=j&&next[j]!=-1)
     {
      if(len[i][j]<kk[j])
      {
       kk[j]=len[i][j];
       next[j]=i;
      }
     }
    }
    next[i]=-1;
    double max=999999999;int k;
    for(j=0;j<num;j++)
    {
     if(kk[j]<max&&next[j]!=-1)
     {
      k=j;
      max=kk[j];
     }
    }
    re[count]=max;
    i=k;
    count++;
   }
  }
}
int main()
{
 int n;
 cin>>n;
 int i;
 while(n--)
 {
  cin>>sa>>num;
  for( i=0;i<num;i++)
  {
   scanf("%lf%lf",&array[i].x,&array[i].y);
  }
  prim(0);
  sort(re,re+num-1);
  printf("%.2f\n",re[num-1-sa]);
 }
 return 0;
}
posted @ 2010-08-18 14:39 崔佳星 阅读(1166) | 评论 (0)编辑 收藏

pku2126 poj2126
题目大意:
给定多项式的系数,问这个多项式能不能分解!
如果能输出NO 否则输出YES
实系数多项式分解定理:
当n<2的时候不能分解输出YES
当n==2的时候如果有实数根就能分解输出NO   否则不能分解输出YES
当n>2的时候一定能分解,那么输出NO

#include<iostream>
using namespace std;
int array[25];
bool root(int a,int b,int c)
{
 if(b*b>=4*a*c)
  return true;
 else
  return false;
}
int main()
{
 int n;
 cin>>n;
 for(int i=0;i<=n;i++)
 {
  cin>>array[i];
 }
 if(n<=1)
  cout<<"YES"<<endl;
 else
  if(n==2)
  {
   if(root(array[0],array[1],array[2]))
    cout<<"NO"<<endl;
   else
    cout<<"YES"<<endl;
  }
  else
   cout<<"NO"<<endl;
  return 0;

}

posted @ 2010-08-17 16:02 崔佳星 阅读(1075) | 评论 (0)编辑 收藏
3096暴力求解,0M通过
#include<stdio.h>
#include<iostream>
#include<cstring>
using namespace std;
char str[85];
char first[3],second[3];
int main()
{
 first[2]='\0',second[2]='\0';
 while(gets(str))
 {
  bool flag=true;
  if(str[0]=='*')
   break;
  int len=strlen(str);
  for(int i=0;i<len;i++)
  {//从第几个开始找起
   for(int j=1;j<(len-1)&&i+j<len;j++)
   {////////这个是间隔
    first[0]=str[i];first[1]=str[j+i];
    for(int k=i+1;k<len&&k+j<len;k++)
    {
     second[0]=str[k];second[1]=str[k+j];
     if(strcmp(first,second)==0)
      flag=false;
    }
    
   }
  }
  if(flag)
   cout<<str<<" is surprising."<<endl;
  else
   cout<<str<<" is NOT surprising."<<endl;
 }
 return 0;
}
posted @ 2010-08-16 11:34 崔佳星 阅读(1084) | 评论 (0)编辑 收藏
这个题就是用一个递归转化数字。10以下的不用转换。
#include<iostream>
using namespace std;
int k;
int ff(int a)
{
 int sum=1;
 for(int i=0;i<a;i++)
  sum*=10;
 return sum;
}
void convert(int a)
{
 if(k/ff(a)==0)
  return ;
 else
 {
  if(k%ff(a)>=ff(a)/2)
   k=k/ff(a)+1;
  else
   k=k/ff(a);
  k*=ff(a);
  convert(a+1);  
 }
}
int main()
{
 int n;
 cin>>n;
 while(n--)
 {
  cin>>k;
  if(k<10)
  {
   cout<<k<<endl;
   continue;
  }
  convert(1);
  cout<<k<<endl;
 }
 return 0;
}
posted @ 2010-08-16 11:01 崔佳星 阅读(850) | 评论 (0)编辑 收藏
仅列出标题
共3页: 1 2 3 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

常用链接

留言簿(1)

随笔分类

随笔档案

文章分类

文章档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜