算法竞赛入门经典 习题笔记

1.排序(permutation)

用1,2,3...9这9个数字组成3个三位数abc,def,ghi,每个数字恰好用一次,要求: abc:def:ghi = 1:2:3.
输出所有的解.提示:不必太动脑筋.
算法思想:确定满足比例关系的3个三位数是否是由9个不同的数组成.可以分离这3个三位数的每一位,用一个长度为>=9的数组标记.假设有数字122;
则数组s[1] = s[2] = 1;类推,可知,若3个三位数由9个不同的数组成,则数组 s[1..9]每一位都为1,即测试s数组元素都为1,或者如果有0则判定不满足条件

#include<iostream>
using namespace std;

void permutation()
{
    int s[10];
    int x, y, z;
    int i, sum;
    // 987/3 = 329, x最大为329即可
    for(x = 123; x <= 329; x++) 
 	{
 		memset(s,0,sizeof(s));
        y = 2 * x;
        z = 3 * x;
        s[x/100] = s[x/10%10] = s[x%10] = 1;
        s[y/100] = s[y/10%10] = s[y%10] = 1;
        s[z/100] = s[z/10%10] = s[z%10] = 1;
        bool m = true;
        for (i = 1; i < 10; i++) 
			if(s[i] == 0)
			{
				m = false;
				break;
			}
		if(m == false )
			continue;
   		printf("%d %d %d\n", x, y, z);
    }
}

int main()
{
    permutation();
	return 0;
} 

 

2.最长回文字串(忽略大小写,会略空格和标点符号)

算法:从一点向两个方向搜,如果遇到不相等的则停止,而且还要区分区间是偶数还是奇数

#include<stdio.h>
#include<string.h>
#include<ctype.h>
#define MAXN 5000 + 10
char buf[MAXN], s[MAXN];  //测试数据 buf[MAXN]="Confuciuss asy: Madam,I'm Adam"
int p[MAXN]; 
int pos;

int main()
{
  	int n, m = 0, max = 0;
  	int i, j, k;
  
 	fgets(buf, sizeof(s), stdin);
  	n = strlen(buf);
  	for(i = 0; i < n; i++)  //排除其中的非字母的放在数组S中,p[m]=i; 在s中第m个对应buf中第i个 
    	if(isalpha(buf[i])) 
    	{
    		p[m] = i;	
  			s[m++] = toupper(buf[i]);
    	}
	int begin,end;
	int cnt = 0;
	for(int i = 0; i < m; ++i)
	{
		begin = i -1;
		end = i + 1; 
		cnt = 1;
		while(begin >= 0 && end < m && s[begin] == s[end]) //奇数个 
		{
			cnt+=2;
			--begin;
			++end;
		}
		if(cnt > max)
		{
			max = cnt;
			pos = begin + 1;
		}
		
		begin = i;
		end = i+1;
		cnt = 0;
		while(begin >=0 && end < m && s[begin] == s[end]) //偶数个 
		{
			cnt+=2;
			--begin;
			++end;
		}
		if(cnt > max)
		{
			max = cnt;
			pos = begin + 1;
		}
	}   
	
  	printf("max = %d\n", max);
  	for(int i = p[pos]; i <= p[pos+max-1]; ++i)
  		printf("%c",buf[i]);
  
  return 0;
}

 

3.周期串

如果一个字符串可以由某个长度k的字符重复多次得到,我们说该串以k为周期。例如: abcabcabcabc以3为周期(注意,它以6和12为周期)。输入一个长度不超过80的串,输出它的最小周期。

样例输入:HoHoHo

样例输出:2

#include<cstdio>
#include<cstring>

using namespace std;

int main()
{
	char s[80+10];
	int k;
	scanf("%s",s);	
	k = strlen(s);
	bool p;
	for(int i = 1; i <= k; ++i)
	{
		p = true;
		for(int j = i; j < k; ++j)
			if(s[j] != s[j%i])
			{
				p = false;
				break;
			}
		if(p)
		{
			printf("%d\n",i);
			break;
		}
	}
	return 0;
}


4.计算两个整数在相加时需要多少次进位。输出两个0为停止。

样例输入:
123  456
 555 555
123  594
0 0
样例输出:
0
3
1

#include<cstdio>
using namespace std;

int main()
{
	int n,m;
	while(scanf("%d %d",&n,&m) == 2)
	{
		if( n == 0 && m == 0) break;
		int cnt = 0;
		int c = 0;
		while(n || m)
		{
			c = (n % 10 + m % 10 + c) > 9 ? 1 : 0;
			cnt += c;
			n /= 10;
			m /= 10;	
		}
		printf("%d\n",cnt);
	} 
	return 0;
} 


5.n的阶乘,n<=1000。

#include<cstdio>
#include<cstring> 
using namespace std;

const int maxn = 3000;
int f[maxn]; 

int  main()
{
	memset(f,0,sizeof(f));
	int i,j;
	int n;
	scanf("%d",&n);
	f[1] = 1; 
	for(i = 2; i <= n; ++i)
	{
		int c = 0, s = 0;
		for(j = 1; j < maxn; ++j)
		{
			s = f[j] * i + c;
			f[j] = s % 10;
			c = s / 10;
		}
	}
	for(j = maxn -1; j >= 1; --j)
		if(f[j]) break;
	for(i = j; i >= 1; --i)
		printf("%d",f[i]);
	printf("\n");
	return 0;
} 


6. 智力题 设置全局变量。

任务1定义int a,b要求在依次执行a=f()和b=f()后a和b的值不同。

任务2定义int a,b要求在依次执行a=(f()+g())+h()和b=f()+(g()+h())后a和b的值不同

注意:依次依次。

#include <stdio.h> 
int c=1; 

int f() 
{    
	c++;    
	return c; 
}  

int g() 
{    
	c++;    
	return c; 
}  

int h() 
{    
	c++;    
	return c; 
}

int main()
{
	int a,b;
	a =f();
	b =f();
	printf("a = %d, b = %d\n",a,b);
}

/*
int main()
{
	int a,b;
	a = f() + f() + h();
	b = f() + (f() + h());
	printf("a = %d, b = %d\n",a,b);
}
*/


7.高精度运算类bign

#include<cstdio>
#include<iostream>

using namespace std;

class bign
{
	private:
		enum{maxn = 200};
		int len, s[maxn];
	public:
		bign();
		bign(int num);
		bign(const char * str);
		bign operator =(int num);
		bign operator =(const char * str);
		string str() const;
		bign operator +(const bign & b) const;
		bign operator -(const bign & b);
		bign operator +=(const bign & b);
		bign operator -=(const bign & b);
		void clean();
		bign operator *(const bign & b);
		bool operator <(const bign & b)  const;
		bool operator <=(const bign & b) const;
		bool operator >(const bign & b)  const;
		bool operator >=(const bign & b) const;
		bool operator ==(const bign & b) const;
		bool operator !=(const bign & b) const;
};

bign::bign()
{
	memset(s,0,sizeof(s));
	len = 0;
}

bign::bign(int num)
{
	*this = num;
}

bign::bign(const char * str)
{
	*this = str;	
}

bign bign::operator=(int num)
{
	bign();
	char s[maxn];
	sprintf(s,"%d",num);
	*this = s;
	return *this;
}

bign bign::operator=(const char *str)
{
	bign();
	len = strlen(str);
	for(int i = 0; i < len; ++i)
		s[i] =  str[len -i - 1] - '0';
	return *this;
}

string bign::str() const
{
	string res = "";
	for(int i = 0; i < len; ++i)
		res = (char)(s[i] + '0') + res;
	if(res == "")
		res = "0";
	return res;
}

bign bign::operator +(const bign & b) const
{
	bign c;
	for(int i = 0, g = 0; g || i < max(len,b.len); ++i )
	{
		int x = g;
		if(i < len) x += s[i];
		if(i < b.len) x += b.s[i];
		g = x / 10;
		c.s[c.len++] = x % 10;
	}
	return c;
	
}

bign bign::operator -(const bign & b)
{
	if(*this < b)
	{
		cout << "the result is nagive/n";
		return bign();
	}
	bign c;
	c.len = 0;
	for(int i = 0, g = 0; i < len; ++i)
	{
		int x = s[i] - g;
		if(i < b.len)
			x -= b.s[i];
		if(x < 0)
		{
			x += 10;
			g = 1;
		}
		else
			g = 0;	
		c.s[c.len++] = x;
	}
	c.clean();
	return c;
}

bign bign::operator +=(const bign & b)
{
	*this = *this + b;
	return *this;	
}

bign bign::operator -=(const bign & b)
{
	*this = *this - b;
	return *this;
}

void bign::clean()
{
	while(len > 0 && s[len - 1] == 0) --len;	
}

bign bign::operator *(const bign & b)
{
	bign c;
	c.len = len + b.len;
	for(int i = 0; i < len; ++i)
		for(int j = 0; j < b.len; ++j)
			c.s[i+j] = s[i] * b.s[j];
	for(int k = 0; k < c.len; ++k)
	{
		c.s[k+1] += c.s[k] / 10;
		c.s[k] %= 10;
	}
	c.clean();
	return c;
}

bool bign::operator <(const bign & b)  const
{
	if(len != b.len)
		return len < b.len;
	for(int i = 0; i < len; ++i)
		if(s[i] != b.s[i])
			return s[i] < b.s[i];
	return false;
}

bool bign::operator <=(const bign & b) const
{
	return !(*this > b); 
}

bool bign::operator >(const bign & b)  const
{
	if(len != b.len)
		return len > b.len;
	for(int i = 0; i < len; ++i)
		if(s[i] != b.s[i])
			return s[i] > b.s[i];
	return false;
}

bool bign::operator >=(const bign & b) const
{
	return !(*this < b);
}

bool bign::operator ==(const bign & b) const
{
	return !(b < *this) && !(*this < b);	
}

bool bign::operator !=(const bign & b) const
{
	return (b < *this) || (*this < b);
}

istream & operator >> (istream & in, bign & x)
{
	string res;
	in >> res;
	x = res.c_str();
	return in;
}

ostream & operator << (ostream & out, const bign & x)
{
	out << x.str();
	return out;
}

8.Cantor数表

题目描述
如下数列,前5项分别是1/1,1/2,2/1,3/1,2/2……。输入n,输出第n项。
1/1 1/2 1/3 1/4 1/5
2/1 2/2 2/3 2/4
3/1 3/2 3/3
4/1 4/2
5/1
样例输入
3
14
7
12345
样例输出
2/1
2/4
1/4
59/99
【算法】
首先要看懂题目是按什么规律来排数的,首先是按斜线,然后,是一条斜线从上到下,另一条斜线从下到上交错的。
然后分析第i条斜线有i个数,前i条斜线一共有S(k)=1+2+3+···+k=k(k+1)/2个数。
n在哪条斜线上呢?只要找到一个最小的正整数k,使得n<=S(k),那么n就是第k条斜线上的第或倒数第S(k)-n+1个元素。
第k条斜线的第i个元素是i/(k+1-i),倒数第i个元素是(k+1-i)/i。

#include<stdio.h>

int main()
{
	int n;
	while(scanf("%d",&n) == 1)
	{
		int k = 1, s = 1;
		while( n > s)
		{
			++k;
			s += k;
		}
		if(k % 2 == 1)
			printf("%d/%d",s-n+1,k+n-s);
		else
			printf("%d/%d",k+n-s,s-n+1);
	}
	return 0;
} 

9.因子和阶乘

输入正整数n(2<=n<=100),把阶乘n!=1*2*3*...*n分解成素因子相乘的形式,从小到大输出各个素数(2、3、5...)的指数。例如,5! 表示为 3,1, 1个2, 3, 5。程序忽略比最大素因子更大的素数(否则末尾会有无穷多个0)。
样例输入:
5
53
样例输出:
5! = 3 1 1
53! = 49 23 12 8 4 4 3 2 2 1 1 1 1 1 1 1

[分析]
因为a^m * a^n = a^(m+n),所以我们只需把所有素因子对应的指数累加起来 。注意,n<=100,即这些素因子不会超过100。我们首先构造一张最大素数为100的素数表,然后用阶乘的每一个数(从小到大)与每一个素数相模,并记录每一个素数的指数。用一个数组p来保存对应的各个素数的指数个数,并标记最大的那个素因子的下标为maxp,最后循环输出到最大下标即可。

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

int is_prime(int n) 
{
  for(int i = 2; i*i <= n; i++)
    if(n % i == 0) return 0;
  return 1;
}

int prime[100], count = 0;

int main() 
{
  int n, p[100];
  for(int i = 2; i <= 100; i++)
    if(is_prime(i)) 
		prime[count++] = i;

  while(scanf("%d", &n) == 1) 
  {
    printf("%d! =", n);
    memset(p, 0, sizeof(p));
    int maxp = 0;
    for(int i = 1; i <= n; i++) 
    {
      int m = i;
      for(int j = 0; j < count; j++)
        while(m % prime[j] == 0) 
		{
          m /= prime[j];
          p[j]++;
          if(j > maxp) maxp = j;
        }
    }
    for(int i = 0; i <= maxp; i++)
      printf(" %d", p[i]);
    printf("\n");
  }
  return 0;
}

10.黑白图像

输入一个n×n的黑白图像(1表示黑色,0表示白色),任务是统计其中八连块的个数。如果两个黑格子有公共边或者公共顶点,就说它们属于同一个八连块。如下图所示的图形有3个八连块。

算法竞赛入门经典 习题笔记_第1张图片

输入
第1行输入一个正整数n(n≤700),此后输入n行,每行是由n个0或1组成的字符串。

输出
在输入黑白图像中,八连块的个数

样例输入

6
100100
001010
000000
110000
111000
010100

样例输出
3

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

const int MAXN = 700 + 10;

int mat[MAXN][MAXN],vis[MAXN][MAXN];

void dfs(int x, int y)
{
	if(!mat[x][y] || vis[x][y])
		return;
	vis[x][y] = 1;
	dfs(x-1,y-1); //左上 
	dfs(x-1,y);//正上 
	dfs(x-1,y+1);//右上 
	dfs(x,y-1);//左边 
	dfs(x,y+1);//右边 
	dfs(x+1,y-1);//左下 
	dfs(x+1,y);//正下 
	dfs(x+1,y+1);//右下 
}

int main()
{
	memset(mat,0,sizeof(mat));
	memset(vis,0,sizeof(vis));
	int n;
	FILE *fp;
	fp = fopen("6.4.1.txt","r");
	fscanf(fp,"%d",&n);
	for(int i = 1; i <= n; ++i)
	for(int j = 1; j <= n; ++j)
		fscanf(fp,"%1d",&mat[i][j]);
	int count = 0;
	for(int i = 1; i <= n; ++i)
	for(int j = 1; j <= n; ++j)
	{
		if(!vis[i][j] && mat[i][j])
		{
			++count;
			dfs(i,j);
		}
	}
	printf("%d\n",count);
	
	return 0;
} 


你可能感兴趣的:(算法,入门,笔记,竞赛,cc++)