自己会的算法模板

头文件

#include<bits/stdc++.h>
using namespace std;

或者

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#include<string>
#include<map>
#include<vector>
using namespace std;
const int INF=0x3f3f3f3f;

 

快速幂

 
int pow_mod(int a,int b,int c)
{
	int ans=1;
	a=a%c;
	while(b)
	{
		if(b&1)	ans=ans*a%c;
		a=a*a%c;
		b>>=1;
	}
	return ans;
}

素数判断

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

素数打表

#include<cstdio> 
#include<cstring>
#include<algorithm>
using namespace std;
int a[(int)1e8+5];
void prime(int n) 
{
	memset(a,0,sizeof(a));
	for(int i=2;i<=n;i++)
		for(int j=2;j*i<=n;j++)
			if(!a[i*j])	a[i*j]=!a[i*j];
	for(int i=2;i<=n;i++)
		if(!a[i])	printf("%-5d",i);
}
int main()
{
	int n;
	while(~scanf("%d",&n))
		prime(n);
	return 0;
}

最大公约数___欧几里得算法(GCD)

#include<cstdio>
int gcd(int a,int b)
{
	return !b?a:gcd(b,a%b);
}
int main()
{
	int a,b;
	while(scanf("%d %d",&a,&b)!=EOF)
		printf("%d\n",gcd(a,b));
	return 0;
}

 

4.拓展欧几里得算法(exgcd)

 

int a,b,x,y;
int exgcd(int a,int b,int &x,int &y)
{
	if(b==0)
	{
		x=1;
		y=0;
		return a;
	}
	int ans=exgcd(b,a%b,y,x);
	y-=x*(a/b);
	return ans;
}

 

 

5.汉诺塔(递归学习)

 

 

#include<cstdio> 
int i=1;
void hanoi(int n,char from,char depend,char to)
{
	if(n==1)
	{
		printf("第%d步:将%d从%c---->%c\n",i++,n,from,to);
		return ;
	}
	else
	{
		hanoi(n-1,from,to,depend);
		printf("第%d步:将%d从%c---->%c\n",i++,n,from,to);
		hanoi(n-1,depend,from,to);
	}
}

int main()
{
	int n;
	while(scanf("%d",&n)!=EOF)
		hanoi(n,'A','B','C');
	return 0;
}

 

6.n皇后(递归学习)

 

 

/*
	在一个n*n的棋盘上放n个皇后
	一共有多少种方法
	放置这些皇后
	
	任意两个皇后不能再同一行,同一列,同一对角线上
	否则会相互攻击 
	 
*/
#include<cstdio>
#include<cmath> 
const int MAXN=1000;
int n;
int p[MAXN];//存放第i行的皇后的列的编号 
void n_queen(int k)//在 0~k-1行皇后已经摆好的情况下,摆放 k 行及其后的皇后 
{
	int i,j;//因为后来要用到,所以提前定义 
	if(k==n)//n个皇后能够全部放下,就输出结果 
	{
		for(i=0;i<n;i++)
			printf("%d ",p[i]+1); //因为列的标号从1开始,所以输出的时候就输出p[i]+1; 
		printf("\n");
		return ; //递归完毕 
	}
	for(i=0;i<n;i++)//逐步尝试第k个皇后的位置 
	{
		for(j=0;j<k;j++)//和前k-1个皇后相比较,看是否在同一行同一列或者在对角线上 
			if(p[j]==i||abs(p[j]-i)==abs(k-j))//有一次这里写了个";",找了半天没找到bug... 
				break;
	
		// i 表示列数, j 表示行数 
		//目的是为了将第 k 行的皇后放在第 i 列 
		//所以从第 0 行开始遍历,判断从 0---k-1 行的皇后 与 第 k行的皇后是否有冲突 
		//	p[j]==i, 如果第 j 行的皇后在第 i 列
		// 第 k 行皇后皇后的位置(k,  i ) //(需要完成的是p[k]=i);  
		// 第 j 行皇后皇后的位置(j,p[j]) 
		//abs(p[j]-i)==abs(k-j)	用来判断第 k 行的皇后与第 j 行的皇后是否在对角线上 

		if(j==k)//当前选的位置与 i 不冲突 
		{
			p[k]=i;	//将第 k 个皇后放在位置 i  
			n_queen(k+1);//第k个皇后放好了,去放第k+1(k<n)个皇后 
		 } 
	}
}
int main() 
{
	while(~scanf("%d",&n))	n_queen(0);//从第 0 个皇后开始放 
	return 0;
}


最长公共子序列(长度+打印路径)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int  maxn=1009;
char a[maxn],b[maxn];
int path[maxn][maxn],dp[maxn][maxn];//path 记录路径 
 
void lcs(int i,int j)//打印路径 
{
	if(i==0||j==0)	return ;//结束标志,a或者b只要有一个找完了,就不在找了 
	if(path[i][j]==1)//path是1的时候输出这个字符 
	{
		lcs(i-1,j-1);//因为是从后往前找的 
		printf("%c",a[i-1]);//所以这句得写到递归函数下边 
	 } 
	else if(path[i][j]==2)
		lcs(i-1,j);
	else 
		lcs(i,j-1);
	return ;
}
 
int main()
{
	while(~scanf("%s %s",a,b))
	{
		memset(dp,0,sizeof(dp));
		int m=strlen(a);
		int n=strlen(b);
		for(int i=1;i<=m;i++)
			for(int j=1;j<=n;j++)
				if(a[i-1]==b[j-1])
				{
					dp[i][j]=dp[i-1][j-1]+1;
					path[i][j]=1;
				}
				else if(dp[i-1][j]>dp[i][j-1])
				{
					dp[i][j]=dp[i-1][j];
					path[i][j]=2;
				}
				else
				{
					dp[i][j]=dp[i][j-1];	
					path[i][j]=3;
				}
		
		lcs(m,n);		
		printf("\n"); 
//		printf("\n%d\n",dp[m][n]);//输出最长子序列的长度 
	}
	return 0;

 

 

最长递增子序列(长度+打印路径)

#include<bits/stdc++.h>
using namespace std;
const int MAXN=105;
int a[MAXN];
int dp[MAXN];
int n;
int vis[MAXN];
void dfs(int pos)//打印路径 
{
	if(pos==-1)	return  ;
	dfs(vis[pos]);
	printf(" %d",pos+1);//这里是正序输出编号(从1开始的) 
}
int main()
{
	while(~scanf("%d",&n)&&n)
	{
		for(int i=0;i<n;i++)
			scanf("%d",&a[i]);
		memset(dp,0,sizeof(dp));
		memset(vis,-1,sizeof(vis));
		int res=0;
		int pos=-1;
		
		for(int i=0;i<n;i++)
		{
			dp[i]=1;
			for(int j=0;j<i;j++)
				if(a[i]>a[j])
				{
					if(dp[i]<dp[j]+1)
					{
						dp[i]=dp[j]+1;
						vis[i]=j;//vis[i]=j 表示以a[i]为结尾的LIS的上一个元素是a[j]		
					}
				}	
			if(res<dp[i])
			{
				res=dp[i];
				pos=i;//找到LIS的最后一个结点 
			}
		}
		printf("The number is %d:",res);//输出LIS的长度 
		dfs(pos);
		printf("\n");
	}
	return 0;
}



背包

01背包

 /*
    根据这个状态转移方程我们可以写出这个代码,复杂度O(nW)
*/
for(int i=0;i<n;i++)
    for(int j=0;j<=W;j++)
        if(j<w[i])  
            dp[i+1][j]=dp[i][j];
        else
            dp[i+1][j]=max(dp[i][j],dp[i][j-w[i]]+v[i]);
printf("%d\n",dp[n][W]);
/*
    此外,01背包的还可以通过两个数组滚动来实现重复利用
*/
int dp[2][MAXN];
for(int i=0;i<n;i++)
    for(int j=0;j<=W;j++)
       if(j<w[i])
          dp[(i+1)&1][j]=dp[i&1][j];
       else
  dp[(i+1)&1][j]=max(dp[i&1][j],dp[i&1][j-w[i]]+v[i]);

printf("%d\n",dp[n&1][W]);
/*
    当然,还可以通过不断重复用一个数组来实现
*/

int dp[MAXN];
for(int i=0;i<n;i++)
    for(int j=W;j>=w[i];j--)
        dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
printf("%d\n",dp[W]);

完全背包

 

每种物品可以挑选任意件

/*
    
*/ 

for(int i=0;i<n;i++)
    for(int j=0;j<=W;j++)
        if(j<w[i])
            dp[i+1][j]=dp[i][j];
        else
            dp[i+1][j]=max(dp[i][j],dp[i+1][j-w[i]]+v[i]);
printf("%d\n",dp[n][W]);

/*
    一维数组
*/
int dp[MAXN];
for(int i=0;i<n;i++)
    for(int j=w[i];j<=W;j++)
        dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
printf("%d\n",dp[W]);

多重背包

每种物品最多可以挑选mi件

for(int i=0;i<n;i++){
    int num=m[i];//用来找a 
    for(int k=1;num>0;k<<=1){
        int mul=min(k,num);
        for(int j=W;j>=w[i]*mul;j--){
            dp[j]=max(dp[j],dp[j-w[i]*mul]+v[i]*mul); 
        }
        num-=mul;
    }
}
printf("%d\n",dp[W]);

 

n!末尾0的个数

int cal(int n)
{
	if(n<5)	return 0;
	n=n/5;
	return n+cal(n);
}


//也可以这样写
int sum=0;
while(n)	sum+=(n/=5);
printf("%d\n",sum);

N的阶乘位数

首先要计算阶乘的位数,以便知道开多大的数组


#include<cstdio>
#include<cmath>
int main()
{
	double sum=0;
	for(int i=1;i<=10000;i++)	// n是10000的情况下 
		sum+=log10(i);
	printf("%d\n",(int)sum+1);
	return 0;
}

第二种求法:运用斯特林公式来计算 n! 的位数

n!\approx \sqrt{2\pi n}(\frac{n}{e})^n

#include<cstdio>
#include<cmath>
#define PI 3.141592654
#define E 2.71828182846 	
int main()
{
	int n,sum=1;
	scanf("%d",&n);
	if(n>3)
		sum=log10(2*PI*n)/2+n*log10(n/E)+1;
	printf("%d\n",sum);
	return 0;
}

 

然后计算

#include<cstdio>
#include<cmath>
#include<cstring> 
int a[35660+5];//储存每一位所得得数 
int main()
{
	int n;
	while(~scanf("%d",&n))
	{
		memset(a,0,sizeof(a));
		int temp,dight=1;
		a[0]=1;
		dight=1;//dight是阶乘的位数 
		for(int i=1;i<=n;i++)
		{
			int num=0;//保存需要进位的数 
			for(int j=0;j<dight;j++)
			{
				temp=a[j]*i+num;//temp是每次相乘的结果 
				a[j]=temp%10;
				num=temp/10;//保存需要进位的数
			}
			while(num)
			{
				a[dight]=num%10;//继续储存 
				num/=10;
				dight++;
			}
		}
		for(int i=dight-1;i>=0;i--)//逆序输出每一位 
			printf("%d",a[i]);
		printf("\n");
	}	
	return 0;
}

更优秀的算法,速度更快,计算范围更大!

#include<cstdio>  
#include<cstring>  
#include<algorithm>  
using namespace std;  
#define ll long long    
const ll c=1e14;  
ll a[10000000];  
int main()  
{  
    ll n;  
    while(~scanf("%lld",&n))   
    {  
        ll temp;  
        ll dight=1;  
        a[0]=1;  
        for(ll i=1;i<=n;i++)  
        {  
            ll num=0;  
            for(ll j=0;j<dight;j++)  
            {  
                temp=a[j]*i+num;  
                a[j]=temp%c;  
                num=temp/c;  
            }  
            if(num!=0)  
            {  
                a[dight++]=num;  
            }  
        }  
        printf("%lld",a[dight-1]);  
        for(ll i=dight-2;i>=0;i--)  
            printf("%014lld",a[i]);//这样也可以   
//            printf("%0.14lld",a[i]);//这里想不明白为什么要加个.   
        printf("\n");  
    }  
    return 0;  
}  
//这个代码可以计算1e4以内的数,超过这个范围的话数据会溢出,需要在修改一下a[i]的最大储存位数 
//就这段代码而言,a[i]最多储存1e14大小的数,要是在乘个1e5的数,结果是1e19大小,肯定会溢出
//所以测试99999!的时候前边出现了负号。。。 

python

import math
n = int(input())
print(math.factorial(n))

 

大斐波那契数

/*
  大斐波那契数 
*/
#include<cstdio>
#include<cstring>
#define ll long long
const int MAXN=1e4+3;
const int c=10000;
ll a[MAXN][MAXN];
int main()
{
	int n;
	while(~scanf("%d",&n))
	{
		a[1][0]=1;a[2][0]=1;//初始化 第一个数和第二个数 
		int dight=0;//斐波那契数的 位数 
		int temp=0;//储存进位
		for(int i=3;i<=n;i++)	//从3算到N
		{
			temp=0;//进位每次计算都要初始化为0
			for(int j=0;j<=dight;j++)
			{
				a[i][j]=a[i-1][j]+a[i-2][j]+temp;
				temp=a[i][j]/10;
				a[i][j]%=10;
			 } 
			if(temp)//如果有进位的话 
			{
				dight++;//位数加一 
				a[i][dight]=temp;//给最高位赋值 
			}
		 } 
		for(int i=dight;i>=0;i--)//逆序输出这个数组 
			printf("%lld",a[n][i]);//n代表是第n个斐波那契数,i是这个数的第i位 
		printf("\n");			
	}
	return 0;
}

应该可以把这个代码优化一下,以便于计算更大的数

/*
  大斐波那契数 
*/
 
//这段代码让每一个a[i][j]的值都是9位 
#include<cstdio>
#include<cstring>
#define ll long long
const int MAXN=1e4+3;
const int c=1e9;
ll a[MAXN][MAXN];
int main()
{
	int n;
	while(~scanf("%d",&n))
	{
		a[1][0]=1;a[2][0]=1;
		int temp=0;
		int d=0;
		for(int i=3;i<=n;i++)
		{
			temp=0;
			for(int j=0;j<=d;j++)
			{
				a[i][j]=a[i-1][j]+a[i-2][j]+temp;
				temp=a[i][j]/c;
				a[i][j]%=c;
			}
			if(temp)
			{
				d++;
				a[i][d]=temp;
			}	
		}	
		printf("%lld",a[n][d]);
		for(int i=d-1;i>=0;i--)
			printf("%010lld",a[n][i]);
		printf("\n");
	}
	return 0;
}

大数加法

/*
	大数加法采用的是模拟的思想,就是利用数组来储存一个数的每一位 
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=10000;
char s1[MAXN],s2[MAXN];
int n1[MAXN],n2[MAXN],sum[MAXN];
int main()
{
	int T;
	scanf("%d",&T);
	for(int k=1;k<=T;k++)
	{
		scanf("%s %s",s1,s2);//用字符串来储存两个大数 
		memset(n1,0,sizeof(n1));//初始化数组,让它们全为0 
		memset(n2,0,sizeof(n2));
		memset(sum,0,sizeof(sum));//初始化保存结果的数组 
		int len1=strlen(s1);//第一个数的长度 
		int len2=strlen(s2);//第二个数的长度 
		int j=0;
		for(int i=len1-1;i>=0;i--)//将第一个数的每一位都逆序赋值给第一个数组 
			n1[j++]=s1[i]-'0';
		j=0;	
		for(int i=len2-1;i>=0;i--)
			n2[j++]=s2[i]-'0';
		int len=len1>len2?len1:len2;//找出来两个数中比较长的那个数 
		int pre=0;//用来保存进位 
		for(int i=0;i<len;i++)//给sum赋值,要记得sum可能是大于9的,输出的时候要对10取余 
		{
			sum[i]=n1[i]+n2[i]+pre/10;	
			pre=sum[i];
		}
		if(pre>9)//保存最高位的是sum[len-1] ,如果大于9 ,结果的位数要加一 
		{
			sum[len]=pre/10;//取高位 
			len++;//位数 +1
		}
		int t=len;
		for(int i=len-1;i>=0;i--)	//去掉前置0 
		{
			if(sum[i]==0)	t--;//像 0001 + 3 这种,结果应该输出 4 而不是0004 
			else			break;
		}
		printf("Case %d:\n%s + %s = ",k,s1,s2);
		for(int i=t-1;i>=0;i--)		
			printf("%d",sum[i]%10);
		printf("\n");
		if(k!=T)	printf("\n");//最后一组数据不要空行 
	 } 
	return 0;
}

大数乘法

/*
	大数乘法: 
	
	运用模拟,两个数组来储存两个大数
	另外一个数组来保存运算结果	
	
	em....
	
*/
 
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=10000;
char s1[MAXN],s2[MAXN];
int a[MAXN],b[MAXN],c[MAXN];
int main() 
{
	while(scanf("%s %s",s1,s2)!=EOF)
	{
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		memset(c,0,sizeof(c));
		int len1=strlen(s1);//第一个数的长度 
		int len2=strlen(s2);//第二个数的长度 
		int i,j;
		for(i=len1-1,j=0;i>=0;i--)	a[j++]=s1[i]-'0';//用数组逆序保存第一个数 
		for(i=len2-1,j=0;i>=0;i--)	b[j++]=s2[i]-'0';//用数组逆序保存第二个数 
		for(i=0;i<len1;i++)		
			for(j=0;j<len2;j++)
				c[j+i]+=a[i]*b[j];//一定要 + *  
		int len=len1+len2;
		for(i=0;i<len;i++)//进行进位运算 
			if(c[i]>9)
			{
				c[i+1]+=c[i]/10;
				c[i]%=10;
			 } 
		int t=len;
		for(i=len-1;i>=0;i--)//去掉前置0 
			if(c[i]==0)	t--;
			else		break;
		for(i=t-1;i>=0;i--)//输出 
			printf("%d",c[i]);		
		printf("\n");
	}	
	return 0;
}

并查集

//#include<bits/stdc++.h>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
const int MAXN=1e3+3;
int pre[MAXN];
int t,n,m;
void init(int n)//初始化 
{
	for(int i=1;i<=n;i++)
		pre[i]=i;
} 
int find(int x)//找根 
{
	return pre[x]==x?x:pre[x]=find(pre[x]);
}
void join(int x,int y)//连接 
{
	x=find(x);
	y=find(y);
	if(x!=y)	pre[x]=y;
}
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d %d",&n,&m);
		init(n);
		
		for(int i=0;i<m;i++)
		{
			int x,y;
			scanf("%d %d",&x,&y);
			join(x,y);
		}
		int ans=0;
		for(int i=1;i<=n;i++)
			if(pre[i]==i)	ans++;
		cout<<ans<<endl;
	}
	return 0;
}

 

Kurskal算法

/*
	依旧是最小生成树的模板题
	用的是Kurskal算法
	因为我只会这一个。。。	
*/
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
struct Road{int x,y,cost;}w;
int pre[105],n,m;
vector<Road> d;		//不定数组,储存道路 
void init(int n)	//初始化元素,元素的根就是自己 
{
	for(int i=1;i<=n;i++)
		pre[i]=i;
}
int find(int x)		//查找元素的根 
{
	return x==pre[x]?x:pre[x]=find(pre[x]);
}
bool cmp(Road a,Road b)//排序的函数,让道路的权值从小到大排列 
{
	return a.cost<b.cost;
}
bool join(int x,int y)//合并元素的根 
{
	x=find(x);
	y=find(y);
	if(x!=y)
	{
		pre[x]=y;
		return true;//合并成功一个元素之后返回 true,以便下边好记录一共有多少元素被并起来了 
	}
	return false;
}
int main()
{
	while(~scanf("%d %d",&n,&m)&&n)	//这里要注意,n 是道路的个数,m是村庄的个数 
	{
		init(m);	//初始化村庄 
		d.clear();	//清空数组 
		for(int i=0;i<n;i++)
		{
			scanf("%d %d %d",&w.x,&w.y,&w.cost);
			d.push_back(w);
		}
		sort(d.begin(),d.end(),cmp);//将道路按权值升序排列 
		int cnt=0;
		int sum=0;
		for(int i=0;i<d.size();i++)
		{
			if(join(d[i].x,d[i].y))
			{
				sum+=d[i].cost;	//道路的权值和 
				cnt++;
			}
			if(cnt==m-1)	break;//好几次这里写成了cnt==n-1,WA的要哭。。 
		}
		if(cnt==m-1)	printf("%d\n",sum);
		else			printf("?\n");
	}
	return 0;
}

 

容斥定理

模板题

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;

ll a[1000000+9],factor[1000],sz;

void p(ll n)
{
    sz=0;
    memset(factor,0,sizeof(factor));
    for(ll i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            factor[sz++]=i;
            while(n%i==0)
                n/=i;
        }
    }
    if(n!=1)    factor[sz++]=n;
}
ll f(ll n)//找 1 ... n 的与 n 不互质的数的个数 
{
    ll ans=0;
    for(int i=1;i<(1<<sz);i++)
    {
        int cnt=0;
        ll m=1; 
        for(int j=0;j<sz;j++)
            if((i>>j)&1)
            {
                cnt++;
                m*=factor[j];
            }
        if(cnt&1)   ans += n/m;
        else        ans -= n/m; 
    }
    return ans;
}

int main()
{
    int t;
    ll a,b,n;
    int kase=0; 
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld %lld %lld",&a,&b,&n);
        p(n);
//      for(int i=0;i<sz;i++)
//          printf("%lld ",factor[i]);
//      printf("\n"); 
        ll ans=b-f(b)-(a-1-f(a-1));
        printf("Case #%d: %lld\n",++kase,ans);
    }
    return 0;
}

 

01背包+输出路径

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=100000+7;
int dp[MAXN];
bool vis[25][MAXN];
int n,W,v[MAXN];
int main()
{
    while(~scanf("%d %d",&W,&n))
    {
        for(int i=0;i<n;i++)
            scanf("%d",&v[i]);
        memset(dp,0,sizeof(dp));
        memset(vis,0,sizeof(vis));
        for(int i=n-1;i>=0;i--)
            for(int j=W;j>=v[i];j--)
                if(dp[j-v[i]]+v[i]>dp[j])
                {
                    dp[j]=dp[j-v[i]]+v[i];
                    vis[i][j]=1;    
                }
        int j=W;
        for(int i=0;i<n;i++)
        {
            if(vis[i][j])
            {
                printf("%d ",v[i]);
                j -= v[i];  
            }   
        } 
        printf("sum:%d\n",dp[W]);

    }
    return 0;
}

 

简单搜索

BFS

#include<bits/stdc++.h>
using namespace std;
const int MAXN=50;
char str[MAXN][MAXN];
bool vis[MAXN][MAXN];
int n,m,ans,stx,sty,edx,edy;
int d[4][2]={0,1, 0,-1, 1,0, -1,0};
struct node{
    int x,y;
    node(){}
    node(int _x,int _y):x(_x),y(_y){}
};

void BFS(int x,int y)
{
    vis[x][y]=1;
    ans++;
    node e1=node(x,y);
    queue<node> que;
    que.push(e1);
    while(que.size())
    {
        node e2=que.front();
        que.pop();
        for(int i=0;i<4;i++)
        {
            int dx=e2.x+d[i][0];
            int dy=e2.y+d[i][1];
            if(dx>=0 && dx<n && dy>=0 && dy<m && !vis[dx][dy] && str[dx][dy]!='#')
            {
                ans++;
                vis[dx][dy]=1;
                que.push(node(dx,dy));
            }
        }
    }
}

int main()
{
    while(~scanf("%d %d",&m,&n)&&(n|m))
    {
        memset(str,0,sizeof(str));
        memset(vis,0,sizeof(vis));
        for(int i=0;i<n;i++)    scanf("%s",str[i]);
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
            {
                if(str[i][j]=='@')
                {
                    stx=i;
                    sty=j;
                    break;
                }
            }
        ans=0;
        BFS(stx,sty);
        printf("%d\n",ans);
    }
    return 0;
}

DFS

#include<bits/stdc++.h>
using namespace std;
const int MAXN=50;
char str[MAXN][MAXN];
bool vis[MAXN][MAXN];
int d[4][2]={1,0, -1,0, 0,1, 0,-1};
int n,m,ans;
int stx,sty,edx,edy;

void DFS(int x,int y)
{
    vis[x][y]=1;
    ans++;
    for(int i=0;i<4;i++)
    {
        int dx=x+d[i][0];
        int dy=y+d[i][1];
        if(dx>=0 && dy>=0 && dx<n && dy<m && !vis[dx][dy] && str[dx][dy]!='#')//判断条件不能搞错 
        {
            vis[dx][dy]=1;
            DFS(dx,dy);
        }
    }
}

int main()
{
    while(~scanf("%d %d",&m,&n)&&(n|m))
    {
        memset(str,0,sizeof(str));//不初始化 Wa 
        memset(vis,0,sizeof(vis));
        for(int i=0;i<n;i++)    scanf("%s",str[i]);
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
            {
                if(str[i][j]=='@')//找到起点 
                {
                    stx=i;
                    sty=j;
                    break;
                }
            }
        ans=0;
        DFS(stx,sty);//从起点开始搜索 
        printf("%d\n",ans);
    }
    return 0;
}

 

最短路DIjkstra

/*
	邻接链表写法 
	
*/
 
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
typedef pair<int,int> P;
const int maxn=1e3+5;
const int INF=0x3f3f3f3f;
 
struct edge
{
	int to,cost;
	edge(){}
	edge(int _to,int _cost)
	{
		to=_to;
		cost=_cost;
	}
};
 
vector<edge> G[maxn];
int d[maxn];
 
void dijkstra(int s)
{
	memset(d,0x3f,sizeof(d));
	d[s]=0;
	priority_queue<P,vector<P>,greater<P> >que;
	que.push(P(0,s));
	while(que.size())
	{
		P p=que.top();que.pop();
		int v=p.second;
		if(d[v]<p.first)	continue;
		for(int i=0;i<G[v].size();i++)
		{
			edge e=G[v][i];
			if(d[e.to]>d[v]+e.cost)
			{
				d[e.to]=d[v]+e.cost;
				que.push(P(d[e.to],e.to));
			}
			
		}
	}
}
 
int main()
{
	int n,m;
	while(~scanf("%d %d",&n,&m)&&(n|m))//n is number of  vertex  ,  m is number of edge
	{
		for(int i=0;i<maxn;i++)	G[i].clear();//一定要记得初始化邻接链表,不然会错 
		for(int i=0;i<m;i++)//
		{
			int x,y,z;
			scanf("%d %d %d",&x,&y,&z);
			G[x].push_back(edge(y,z));
			G[y].push_back(edge(x,z));
		}
		dijkstra(1);
		printf("%d\n",d[n]); 
	}
	return 0;
}

分治找逆序数

#include<cstdio>
#include<cstring>
//#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=50005;
 
int a[maxn],b[maxn];
int count;
int n;
 
void merge(int a[],int start,int mid,int end)
{
	int i=start,j=mid+1,k=start;
	while(i<=mid&&j<=end)
	{
		if(a[i]<=a[j])
		{
			b[k++]=a[i++];
		}
		else
		{
			count+=j-k;
			b[k++]=a[j++];
		}
	}
	while(i<=mid)
	{
		b[k++]=a[i++];
	}
	while(j<=end)
	{
		b[k++]=a[j++];
	}
	for(int i=start;i<=end;i++)
	{
		a[i]=b[i];
	}
}
void mergesort(int *a,int start,int end)
{
	if(start<end)
	{
		int mid=(start+end)/2;
		mergesort(a,start,mid);
		mergesort(a,mid+1,end);
		merge(a,start,mid,end);
	}
}
 
int main()
{
	while(~scanf("%d",&n))
	{
		for(int i=0;i<n;i++)	scanf("%d",a+i);
		count=0;
		mergesort(a,0,n-1);
		printf("%d\n",count);
	}
	return 0;
}

2

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
vector<int>	A;
int n;
ll merge_count(vector<int> &a)
{
	int n=a.size();
	if(n<=1)	return 0;
	
	ll cnt=0;
	vector<int> b(a.begin(),a.begin()+n/2);
	vector<int> c(a.begin()+n/2,a.end());
	cnt += merge_count(b);
	cnt += merge_count(c);
	
	int ai=0,bi=0,ci=0;
	while(ai<n)
	{
		if(bi<b.size() && (ci == c.size() || b[bi] <= c[ci]))
			a[ai++] = b[bi++];
		else
		{
			cnt += n / 2 - bi;
			a[ai++] = c[ci++]; 
		}
	}
	return cnt;
}
int main()
{
	while(~scanf("%d",&n)&&n)
	{
		int x;
		A.clear();
		for(int i=0;i<n;i++)
		{
			scanf("%d",&x);
			A.push_back(x);
		}
		printf("%lld\n",merge_count(A));
	}
	return 0;
}

平面分治

 

#include<bits/stdc++.h>
using namespace std;
typedef pair<double,double> P;
const int MAXN=100005;
const int INF=0x3f3f3f3f;
int n;
P A[MAXN];
bool compare_y(P a,P b)
{
    return a.second<b.second;
 } 
double closest_pair(P *a,int n)
{
    if(n<=1)    return INF;
    int m=n/2;
    double x=a[m].first;
    double d=min(closest_pair(a,m),closest_pair(a+m,n-m));
    inplace_merge(a,a+m,a+n,compare_y);
    vector<P> b;
    for(int i=0;i<n;i++)
    {
        if(fabs(a[i].first-x)>=d)   continue;
        for(int j=0;j<b.size();j++)
        {
            double dx=a[i].first-b[b.size()-j-1].first;
            double dy=a[i].second-b[b.size()-j-1].second;
            if(dy >= d) break;
            d=min(d,sqrt(dx*dx+dy*dy));
        }   
        b.push_back(a[i]);
    } 
    return d;   
}
int main()
{
    while(~scanf("%d",&n)&&n)
    {
        for(int i=0;i<n;i++)
            scanf("%lf %lf",&A[i].first,&A[i].second);
        sort(A,A+n);
        printf("%.2lf\n",closest_pair(A,n)/2.0);
    }
    return 0;
}

平面的分治法,只不过这道题把点分成了两个集合,所以我们需要标记一下,在同一个集合里的元素,让它们计算出来的距离为INF 
就好了

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

const int MAXN=200005;
const double INF=1e30;

struct node{
    double x,y;
    int flag;
}s[MAXN],re[MAXN]; 

bool cmpx(node a,node b)
{
    return a.x<b.x;
}
bool cmpy(node a,node b)
{
    return a.y<b.y;
}
double dis(node a,node b)
{
    if(a.flag == b.flag)    return INF;
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

double slove(int l,int r)
{
    if(l == r)  return INF;
    int mid=(l+r)>>1;
    int cnt=0;
    double ans=min(slove(l,mid),slove(mid+1,r));
    for(int i=l;i<=r;i++)
        if(fabs(s[i].x-s[mid].x) <= ans)
            re[cnt++]=s[i];
    sort(re,re+cnt,cmpy);
    for(int i=0;i<cnt;i++)
        for(int j=i+1;j<cnt;j++)
            if(re[j].y-re[i].y>ans)
                break;
            else
                ans=min(ans,dis(re[i],re[j]));
    return ans;
}
int main()
{
    int n,t;
    scanf("%d",&t);
    while(t--)
    {
        memset(re,0,sizeof(re));
        memset(s,0,sizeof(s));
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%lf %lf",&s[i].x,&s[i].y);
            s[i].flag=0;
        }
        for(int i=n;i<2*n;i++)
        {
            scanf("%lf %lf",&s[i].x,&s[i].y);
            s[i].flag=1;
        }           
        sort(s,s+2*n,cmpx);
        printf("%.3lf\n",slove(0,2*n-1));
    }
    return 0;
}

map的二维用法

#include<iostream>
#include<string>
#include<cstdio>
#include<map>

using namespace std;

int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        map<string ,map<string,int> > p;
        string s1,s2;
        int x;

        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            cin>>s1>>s2>>x;
            p[s2][s1]+=x;
        }
        for(map<string ,map<string,int> >:: iterator ite=p.begin();ite!=p.end();ite++)
        {
            cout<<ite->first<<endl;
            for(map<string,int>::iterator ite2=ite->second.begin();ite2!=ite->second.end();ite2++)
            {
                cout<<"   |----"<<ite2->first<<"("<<ite2->second<<")"<<endl;
            }
        }
        if(t)   cout<<endl;
    }
    return 0;
}

 

KMP 找下标

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e6+7;
int s[MAXN],p[MAXN];
int slen,plen;
int nex[MAXN];

void GetNext()
{
    int i,j;
    i=0;
    j=nex[0]=-1;
    while(i<plen)
    {
        while(-1!=j&&p[i]!=p[j])    j=nex[j];
        if(p[++i]==p[++j])  nex[i]=nex[j];
        else                nex[i]=j;
    }
}

int KMP()
{
    GetNext();
    int i,j;
    i=j=0;
    while(i<slen&&j<plen)
    {
        while(-1!=j && s[i]!=p[j])  j=nex[j];
        i++;j++;
    }
    if(j==plen)
        return i-j+1;
    else
        return -1;
}


int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d",&slen,&plen);
        for(int i=0;i<slen;i++) scanf("%d",&s[i]);
        for(int i=0;i<plen;i++) scanf("%d",&p[i]);
        printf("%d\n",KMP());
    }
    return 0;
}





 

Catalan数

#include<bits/stdc++.h>
using namespace std;
const int MAXN=110;
int a[MAXN][MAXN];//a[i][0] save the length

void GetCatalans()
{
    int carry=0;
    int len=1;
    a[1][1]=1; a[1][0]=1;
    a[2][1]=2; a[2][0]=1;
    for(int i=3;i<MAXN;i++)
    {
        carry=0;
/*************************大数乘法********************************/
        for(int j=1;j<=len;j++)
        {
            int sum = a[i-1][j]*(i*4-2) + carry;
              carry = sum / 10;
            a[i][j] = sum%10;
        }
        while(carry)
        {
            a[i][++len] = carry%10;
            carry /= 10;
        }
/**************************大数除法********************************/

        for(int j=len;j>0;j--)
        {
            int sum = a[i][j] + carry*10;
            a[i][j] = sum / (i+1);
              carry = sum % (i+1);
        }
        while(a[i][len]==0) len--;
        a[i][0]=len;
    }
}
int main()
{
    int n;
    GetCatalans();
    while(~scanf("%d",&n))
    {
        for(int i=a[n][0];i>0;i--)
            printf("%d",a[n][i]);
        printf("\n");
    }
    return 0;
}

杜教BM模板

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <cassert>
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1000000009;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
// head

int _;
ll n;
namespace linear_seq {
    const int N=10010;
    ll res[N],base[N],_c[N],_md[N];

    vector<int> Md;
    void mul(ll *a,ll *b,int k) {
        rep(i,0,k+k) _c[i]=0;
        rep(i,0,k) if (a[i]) rep(j,0,k) _c[i+j]=(_c[i+j]+a[i]*b[j])%mod;
        for (int i=k+k-1;i>=k;i--) if (_c[i])
            rep(j,0,SZ(Md)) _c[i-k+Md[j]]=(_c[i-k+Md[j]]-_c[i]*_md[Md[j]])%mod;
        rep(i,0,k) a[i]=_c[i];
    }
    int solve(ll n,VI a,VI b) { // a 系数 b 初值 b[n+1]=a[0]*b[n]+...
//        printf("%d\n",SZ(b));
        ll ans=0,pnt=0;
        int k=SZ(a);
        assert(SZ(a)==SZ(b));
        rep(i,0,k) _md[k-1-i]=-a[i];_md[k]=1;
        Md.clear();
        rep(i,0,k) if (_md[i]!=0) Md.push_back(i);
        rep(i,0,k) res[i]=base[i]=0;
        res[0]=1;
        while ((1ll<<pnt)<=n) pnt++;
        for (int p=pnt;p>=0;p--) {
            mul(res,res,k);
            if ((n>>p)&1) {
                for (int i=k-1;i>=0;i--) res[i+1]=res[i];res[0]=0;
                rep(j,0,SZ(Md)) res[Md[j]]=(res[Md[j]]-res[k]*_md[Md[j]])%mod;
            }
        }
        rep(i,0,k) ans=(ans+res[i]*b[i])%mod;
        if (ans<0) ans+=mod;
        return ans;
    }
    VI BM(VI s) {
        VI C(1,1),B(1,1);
        int L=0,m=1,b=1;
        rep(n,0,SZ(s)) {
            ll d=0;
            rep(i,0,L+1) d=(d+(ll)C[i]*s[n-i])%mod;
            if (d==0) ++m;
            else if (2*L<=n) {
                VI T=C;
                ll c=mod-d*powmod(b,mod-2)%mod;
                while (SZ(C)<SZ(B)+m) C.pb(0);
                rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
                L=n+1-L; B=T; b=d; m=1;
            } else {
                ll c=mod-d*powmod(b,mod-2)%mod;
                while (SZ(C)<SZ(B)+m) C.pb(0);
                rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
                ++m;
            }
        }
        return C;
    }
    int gao(VI a,ll n) {
        VI c=BM(a);
        c.erase(c.begin());
        rep(i,0,SZ(c)) c[i]=(mod-c[i])%mod;
        return solve(n,c,VI(a.begin(),a.begin()+SZ(c)));
    }
};

int main() {
    while (~scanf("%lld",&n)) {
        vector<int>v;
        v.push_back(0);
        v.push_back(1);
        v.push_back(1);
        v.push_back(2);
        v.push_back(3);
        v.push_back(5);
        //VI{1,2,4,7,13,24}

        printf("%d\n",linear_seq::gao(v,n));
    }
}

线段树维护区间最大值

/*
    HDU 1166敌兵布阵
*/

#include<bits/stdc++.h>
using namespace std;
const int MAXNODE=1<<20;
const int MAXN=2e6+3;
struct NODE{
    int l,r,v;
}node[MAXNODE];
int father[MAXN];

void bt(int i,int l,int r)//建树0
{
    node[i].l=l;
    node[i].r=r;
    node[i].v=0;
    if(l == r)
    {
        father[l]=i;
        return ;
    }
    bt(i<<1, l, (l+r)/2);
    bt(i<<1|1, (l+r)/2 + 1, r);
}
void update(int ri)//更新树
{
    if(ri == 1) return ;
    int fi = ri/2;
    int a=node[fi<<1].v;
    int b=node[fi<<1|1].v;
    node[fi].v= a+b ;
    update(ri/2);
}
int Max;
void query(int i,int l,int r)//要查寻的区间[l,r];
{
    if(node[i].l==l && node[i].r == r)// 第i个结点 刚好保存的是[l,r]的最大值
    {
        Max +=  node[i].v;
        return ;
    }
    i<<=1;//左儿子结点
    if(l <= node[i].r)
    {
        if(r <= node[i].r)  query(i,l,r);
        else        query(i,l,node[i].r);
    }
    i++;//右儿子结点
    if(r >= node[i].l)
    {
        if(l >= node[i].l)  query(i,l,r);
        else        query(i,node[i].l,r);
    }
}


int main()
{
    int t,n,m,g;
    ios::sync_with_stdio(false);
    cin>>t;
    int num=1;
    while(t--)
    {
        cin>>n;
        bt(1,1,n);
        for(int i=1;i<=n;i++)
        {
            cin>>g;
            node[father[i] ].v = g;
            update(father[i]);
        }
        string op;
        int i,j;
        cout<<"Case "<<num++<<":"<<endl;
        while(cin>>op && op[0]!='E')
        {
            cin>>i>>j;
            if(op[0]=='Q')
            {
                Max=0;
                query(1,i,j);
                cout<<Max<<endl;
            }
            if(op[0]=='A')
            {
                node[father[i] ].v += j;
                update(father[i]);
            }
            if(op[0]=='S')
            {
                node[father[i] ].v -= j;
                update(father[i]);
            }
        }

    }
    while(cin>>n>>m)
    {
        bt(1,1,n);
        for(int i=1; i<=n; i++)
        {
            cin>>g;
            node[father[i] ].v = g;
            update(father[i]);
        }
        string op;
        int a,b;
        while(m--)
        {
            cin>>op>>a>>b;
            if(op[0] == 'Q')
            {
                Max=0;
                query(1,a,b);
                cout<<Max<<endl;
            }
            else
            {
                node[father[a] ].v = b;
                update(father[a]);
            }
        }

    }
    return 0;
}

自适应辛普森法

/*
    HDU 1724
*/

#include<bits/stdc++.h>
using namespace std;
const double PI = 3.1415926;
int a,b,l,r;
/**********************************/


double F(double x)
{
        return sqrt(b*b*(a*a-x*x)/(a*a));//Simpson公式用到的函数
}
double simpson(double a, double b)//三点Simpson法,这里要求F是一个全局函数
{
        double c=a+(b-a)/2;
        return (F(a)+4*F(c)+F(b))*(b-a)/6;
}
double asr(double a, double b, double eps, double A)//自适应Simpson公式(递归过程)。已知整个区间[a,b]上的三点Simpson值A
{
        double c=a+(b-a)/2;
        double L=simpson(a,c),R=simpson(c,b);
        if(fabs(L+R-A)<=15*eps) return L+R+(L+R-A)/15.0;
        return asr(a,c,eps/2,L)+asr(c,b,eps/2,R);
}
double asr(double a,double b,double eps)//自适应Simpson公式(主过程)
{
        return asr(a,b,eps,simpson(a,b));
}


/********************************************/
int main()
{
        int t;
        scanf("%d",&t);
        while(t--)
        {
                scanf("%d %d %d %d",&a,&b,&l,&r);
                printf("%.3lf\n",asr(l,r,(1e-6))*2);
        }
        return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值