算法复习

在这里插入图片描述

优先队列

q.push(k);//在q的末尾插入k
q.pop();//删掉q的第一个元素
q.top();//返回q的第一个元素

sort

默认从小到大排序
bool cmp(node a,node b) //函数名任意取,该函数为bool形
{
if(a.y==b.y) //如果两个结构体的y相同,按它们的x值从小到大排列
return a.x<b.x;
else return a.y<b.y; // 反之按y从小到大排列
}
我习惯保存数组使用下标1—n 此时应为sort(a+1,a+n+1,cmp)

struct

struct Student //不需加typedef
    {
    int a;
    };    
    于是就定义了结构体类型Student,声明变量时直接Student stu2;

递推

快速模幂a^b%m

 int ans = 1, base = a
 while(b > 0)
    {
        if(b & 1)
        {
            ans *= base;
            ans %= m;
        }

        base *= base;
        base %= m;
        b >>= 1;
    }

在这里插入图片描述

分治

#include<iostream>
#include<vector>
long long num_of_pairs = 0;
using namespace std;
int main()
{
    void mergesort(int first, int last, vector<int>&v);
    void merge(int first, int mid, int last, vector<int>&v);
    int num, data;
    vector<int> v1;
    cin >> num;
    
    for (int i = 0; i < num; i++)
    {
        cin >> data;
        v1.push_back(data);
    }//输入数据
    mergesort(0, num - 1, v1);
        cout << num_of_pairs << endl;
    v1.clear();
    
    return 0;
}
void merge(int first, int mid, int last, vector<int>&v)
{

    vector<int> temp(last - first + 1);//临时vector用于存放排顺序//的数据
    int i = first, j = mid + 1, k = 0;
    while (i <= mid&&j <= last)
    {
        if (v[i] <= v[j])
        {
            temp[k++] = v[i++];
        }
        else {
            temp[k++] = v[j++];
            num_of_pairs += (mid - i + 1);
            //归并时,左序列和右序列分别为有序数列,因而若v[i]>v[j]
            //则从v[i]...v[mid]均大于v[j],因而v[i]>v[j],可以得到有mid-i+1个逆序对
        }
    }
    while (i <= mid)
    {
        temp[k++] = v[i++];
    }
    while (j <= last)
    {
        temp[k++] = v[j++];
    }
    for (i = 0; i <last - first + 1; i++)
    {
        v[first + i] = temp[i];
    }
}
void mergesort(int first, int last, vector<int>&v)
{
    if (first < last)
    {
        int mid = (first + last) / 2;
        mergesort(mid + 1, last, v);
        mergesort(first, mid, v);
        merge(first, mid, last, v);
    }

}

动态规划

二叉苹果树

int sz[maxn]; 树枝数目
void dfs(int u,int fa){
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].to;if(v==fa)continue;
        dfs(v,u);sz[u]+=sz[v]+1; 
        for(int j=min(sz[u],m);j;--j)        倒序01背包
            for(int k=min(sz[v],j-1);k>=0;--k)
                f[u][j]=max(f[u][j],f[u][j-k-1]+f[v][k]+e[i].w);
    }
}

树形dp最大子树和

void dfs(int u,int fa)//u为当前节点,fa为u的爸爸
{
    f[u]=a[u];  //先给f[u]赋初值,就是u本身的美观指数
    for(int i=head[u];i;i=tree[i].next) //找儿子
    {
        int v=tree[i].to;  
        if(v!=fa)  //之前加的双向边,可能跑回去
        {
            dfs(v,u);  //继续向下找
            f[u]+=max(0,f[v]);  //状态转移
        }
    }
    ans=max(ans,f[u]); //更新ans
}

上司下属

void dfs(int root){
14     for(int i=0; i<G[root].size(); i++){
15         dfs(G[root][i]);
16     }
17     for(int i=0; i<G[root].size(); i++){
18         dp[root][0] += max(dp[G[root][i]][0], dp[G[root][i]][1]);
19         dp[root][1] += dp[G[root][i]][0];
20     }
21 }

士兵

define mst(s, t) memset(s, t, sizeof(s))
 9 const int INF = 0x3f3f3f3f;
10 const int maxn = 1510;
11 int dp[maxn][2], father[maxn];
12 vector<int> G[maxn];
13 void dfs(int root){
14     for(int i=0; i<G[root].size(); i++){
15         dfs(G[root][i]);
16     }
17     for(int i=0; i<G[root].size(); i++){
18         dp[root][0] += dp[G[root][i]][1];
19         dp[root][1] += min(dp[G[root][i]][0], dp[G[root][i]][1]);
20     }
21 }
22 int main() 
23 {
24     //freopen("in.txt", "r", stdin);
25     int n;
26     while( scanf("%d", &n) != EOF){
27         for(int i=0; i<=n; i++){
28             G[i].clear();
29             dp[i][1] = 1,  dp[i][0] = 0;
30             father[i] = -1;
31         }
32         for(int i=0; i<n; i++){
33             int root, node, cnt;
34             scanf("%d:(%d)",&root, &cnt);
35             for(int i=0; i<cnt; i++){
36                 scanf("%d", &node);
37                 G[root].push_back(node);
38                 father[node] = root;
39             }
40         }
41         int root = 1;
42         while(father[root] != -1) root=father[root];
43         dfs(root);
44         printf("%d\n", min(dp[root][0], dp[root][1]));
45     }
46     return 0;
47 }

地图 马拦卒

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ull unsigned long long
using namespace std;
const int fx[]={0,-2,-1,1,2,2,1,-1,-2};
const int fy[]={0,1,2,2,1,-1,-2,-2,-1};
//马可以走到的位置
int bx,by,mx,my;
ull f[30][30];//f[i][j]代表从A点到(i,j)会经过的线路数
bool s[30][30];//判断这个点有没有马盯着
int main(){
    scanf("%d%d%d%d",&bx,&by,&mx,&my);
    ++bx; ++by; ++mx; ++my;
    //坐标+1以防越界
    f[1][1]=1;//初始化
    s[mx][my]=1;//标记马的位置
    for(int i=1;i<=8;i++)
        s[ mx + fx[i] ][ my + fy[i] ]=1;
    for(int i=1;i<=bx;i++){
        for(int j=1;j<=by;j++){
            if(s[i][j])continue;
            f[i][j]=max( f[i][j] , f[i-1][j] + f[i][j-1] ); 
            //状态转移方程
        }
    }
    printf("%llu\n",f[bx][by]);
    return 0;
} 

钢管切割-- 一个划分成n个

#include <iostream>
#include <cstring> 
using namespace std; 
const int lenmax =1000+5;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int t[lenmax];
int dp[lenmax];
int main(int argc, char** argv) {
	
	int n;
	while(~scanf("%d",&n))
	{
		memset(dp,0x3f,sizeof dp);
		int i,j;
		for(i=1;i<=n;i++)
		{
			scanf("%d",&t[i]);
		}
		dp[1]=t[1];
		dp[0]=0;   //初始化
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=i;j++)
			{
				dp[i]=min(t[j]+dp[i-j],dp[i]);
			}
		}
		printf("%d\n",dp[n]); 
	}
	
	return 0;
}

背包

#include <iostream>
#include<algorithm>
#include<cstdio> 


using namespace std;


void f(int n,int k,int c[],int w[],int m[])
{
	int v[30005]={0};
	int i,j,t;
	for(i=1;i<=n;i++)
	{
		if(m[i]==233||c[i]*m[i]>k)
		{
			for(j=c[i];j<=k;j++)
			{
				v[j]=max(v[j],v[j-c[i]]+w[i]);
			}
		}  //完全背包 
		else{
			int num=m[i];
		          //不要忘记这个条件 
    		for (t = 1; num > 0; t <<= 1) {
				if (t > num) t = num;
				num -= t;
				for ( j = k; j >= c[i] * t; j--)
            		v[j] = max(v[j], v[j - c[i] * t] + w[i] * t);
    									}
		
		} //01背包 
	}
	printf("%d\n",v[k]); 
}
int main()
{
	int n,k;
	while(~scanf("%d %d",&n,&k))
	{
		int c[505]={0};//????
		int w[505]={0}; //???? 
		int m[505]={0};
		
		int i;
		for(i=1;i<=n;i++)
		{
			scanf("%d %d %d",&c[i],&w[i],&m[i]);
		}
		f(n,k,c,w,m);
	
	}
	return 0;
}

矩阵链相乘–n个归并成一个

#include <iostream>
#include <cstdio>
#include <climits>
using namespace std; 

/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int mintimes(int p[],int m[][305],int s[][305],int n)
{
	int i,k,l;
	for(i=1;i<=n;i++)
		m[i][i]=0;
	for(l=2;l<=n;l++)   //矩阵链长度从2到n 
	{
		for(i=1;i<=n+1-l;i++)  //矩阵链开始位置
			{
				m[i][i+l-1]= INT_MAX;
				for(k=i;k<i+l-1;k++)
				{
					if(m[i][i+l-1]>=m[i][k]+m[k+1][i+l-1]+p[i-1]*p[k]*p[i+l-1])
					{
					
						m[i][i+l-1]=m[i][k]+m[k+1][i+l-1]+p[i-1]*p[k]*p[i+l-1];
						s[i][i+l-1]=k;
					}
				}
			} 
	}
	return m[1][n];
		
}
void print_method(int s[][305],int i,int j)
{
	if(i==j)
	{
		printf("A%d",i);
		return;
	}
	int k=s[i][j];
	printf("(");
	print_method(s,i,k);
	print_method(s,k+1,j);
	printf(")");
}


int main(int argc, char** argv) {
	int n;
	int p[305];
	int m[305][305],s[305][305]; //m[i][j] 从第i个到第个j矩阵链的乘法次数 
	while(~scanf("%d",&n))
	{
		int i;
		for(i=0;i<=n;i++)
			scanf("%d",&p[i]);
		int times = mintimes(p,m,s,n);
		printf("%d\n",times);
		print_method(s,1,n);
		printf("\n");
	}
	return 0;
}

OBST

#include <iostream>
using namespace std; 
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
const int maxn=500+5;
const int MAX = 2147483647;

int obst(int n,int p[],int q[])
{
	int e[maxn][maxn];  //包含ki---kj关键字的搜索代价 
	int w[maxn][maxn];  //包含ki---kj关键字的出现次数  
	int i,j,r,len;
	for(i=1;i<=n+1;i++)
	{
		e[i][i-1]=q[i-1]; 
		w[i][i-1]=q[i-1];
	}

	/*for(i=1;i<=n;i++)
	{
		for(j=i;j<=n;j++)
		{
			w[i][j]=w[i][j-1]+p[j-1]+q[j-1];
		}
	}*/
	for(len=1;len<=n;len++)  //子树长度 
	{
		for(j=1;j+len-1<=n;j++) //起点 
		{
			int k=j+len-1;
			w[j][k]=w[j][k-1]+p[k]+q[k]; 
			int min=MAX;  //注意min的位置,要恢复 
			for(r=j;r<=j+len-1;r++) 
			{ //根节点 
				if(e[j][r-1]+e[r+1][k]+w[j][k]<min)
				{
					min=e[j][r-1]+e[r+1][k]+w[j][k];
				}
			}
			e[j][k]=min;
		}
	}
	return e[1][n];
}

int main(int argc, char** argv) {
	int n;
	scanf("%d",&n);
	int p[maxn]; //关键字搜索次数 
	int q[maxn]; //伪关键字搜索次数 
	int i;
	for(i=1;i<=n;i++)
	{
		scanf("%d",&p[i]);
	}
	for(i=0;i<=n;i++)          //比上一行多一个数从0开始! 
	{
		scanf("%d",&q[i]);
	}
	printf("%d",obst(n,p,q));
	
	return 0;
}

贪心算法

做出每个贪心选择后产生一个子问题。求表达式,交换两个选择,探寻最优选择。常用优先队列优化选择

活动选择问题

n个活动1个资源任意活动进行时唯一占用该资源
原则:最早结束,最早开始,最短时间

#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
const int maxn= 1000;
typedef pair<int,int>p;
p act[maxn];
p choose[maxn];
/*struct cmp
{
	bool operator ()(p &a,p &b)
	{
		return a.second>b.second;
	}
};*/
bool cmp (p a,p b)
{
	return a.second<b.second;
}
//priority_queue<p,vector<p>,cmp>que;
int main(int argc, char** argv) {
	int n;
	scanf("%d",&n);
	int i;
	for(i=1;i<=n;i++)
	{
		scanf("%d%d",&act[i].first,&act[i].second);
		//que.push(act[i]);
	}
	/*int j=1;
	choose[j++]=que.top();
	que.pop();
	while(!que.empty()){
		if(que.top().first>=choose[j-1].second)
		{
			choose[j++]=que.top();
			
			
		}
		que.pop();
		
	}
	printf("%d",j-1);*/
	sort(act,act+n,cmp);
	int num=1,j;
    i=1;
    for(j=2;j<=n;j++)
    {
        if(act[j].first>act[i].second)//每次选取结束时间最早的活动
        {
            i=j;
            num++;
            printf("%d %d\n",i,act[i].second);
        }
    }
    printf("%d",num); 
	
	return 0;
}

分数背包

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std; 
const int maxn = 100000+7;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
 struct trash
{
	int ti;
	int mi;
	double fra;
} ;
trash a[maxn];

bool cmp(trash x, trash y)
{
	return x.fra >y.fra ;
}

int main(int argc, char** argv) {
	int n,t,i;
	scanf("%d %d",&n,&t);
	for(i=1;i<=n;i++){
	
		scanf("%d%d",&a[i].ti,&a[i].mi );
		a[i].fra =(double)a[i].mi/(double)a[i].ti; //注意精度转换 
	}
	sort(a+1,a+n+1,cmp);
	int num=t;
	double ans=0;
	for(i=1;i<=n&&num>0;i++)
	{
		if(num<a[i].ti){ 
			ans+=num*a[i].fra;
			num=0;     }     //注意循环条件,变量的更新!! 
		else{ 
			ans+=a[i].mi ;
			num-=a[i].ti ;
		} 
	}
	printf("%.2f",ans);
	return 0;
}

最小生成树

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=2e5+10;
int pre[5010];
struct node
{
	int u,v;
	int value;
}p[maxn];
 
void init(int n)
{
	for(int i=1;i<=n;i++)
	{
		pre[i]=i;
	}
}
 
int find(int x)
{
	if(pre[x]==x) return x;
	return pre[x]=find(pre[x]);
}
 
bool cmp (node x,node y)
{
	return x.value<y.value;
}
 
void mix(int x,int y)
{
	int fx=find(x);
	int fy=find(y);
	if(fx!=fy)
	{
		pre[fy]=fx;
	}
}
 
int main()
{
	int  n,m;
     scanf("%d%d",&m,&n);   //m 点 n 边 
	{
		
		for(int i=1;i<=n;i++)
		{
			scanf("%d%d%d",&p[i].u,&p[i].v,&p[i].value);
		}
		sort(p+1,p+n+1,cmp);
		int num=0,ans=0;
		init(m);
		for(int i=1;i<=n&&num<m-1;i++)
		{
			int fx=find(p[i].u);
			int fy=find(p[i].v);
			if(fx!=fy)
			{
				pre[fy]=fx;
				num++;
				ans+=p[i].value;
			}
		}
		if(num==m-1)
		{
			printf("%d\n",ans);
		}
		else
		{
			printf("orz\n");
		}
	}
	return 0;
}

动态规划

背包

#include <iostream>
#include<algorithm>
#include<cstdio> 


using namespace std;


void f(int n,int k,int c[],int w[],int m[])
{
	int v[30005]={0};
	int i,j,t;
	for(i=1;i<=n;i++)
	{
		if(m[i]==233||c[i]*m[i]>k)
		{
			for(j=c[i];j<=k;j++)
			{
				v[j]=max(v[j],v[j-c[i]]+w[i]);
			}
		}  //完全背包 
		else{
			int num=m[i];
		          //不要忘记这个条件 
    		for (t = 1; num > 0; t <<= 1) {
				if (t > num) t = num;
				num -= t;
				for ( j = k; j >= c[i] * t; j--)
            		v[j] = max(v[j], v[j - c[i] * t] + w[i] * t);
    									}
		
		} //01背包 
	}
	printf("%d\n",v[k]); 
}
int main()
{
	int n,k;
	while(~scanf("%d %d",&n,&k))
	{
		int c[505]={0};//????
		int w[505]={0}; //???? 
		int m[505]={0};
		
		int i;
		for(i=1;i<=n;i++)
		{
			scanf("%d %d %d",&c[i],&w[i],&m[i]);
		}
		f(n,k,c,w,m);
	
	}
	return 0;
}

图算法

dfs

食物链数 基本路个数

在这里插入图片描述在这里插入图片描述

dfs板子

int cnt=0;
void dfs(int start,int cnt)//start 
{
	int i;
	if(check())
	{
		return;
	}

	for(i=start;i<=g;i++)
	{
		
		if(!marked[i])
		{
			marked[i]=true;		  //入栈 
			que.push_back(i);
			dfs(i,cnt+1);
			marked[i]=false;  //出栈 
			que.pop_back();
		}
	}

}

bfs矩阵连通分量

#include <iostream>
#include <deque>
#include<cstring>
using namespace std; 
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

struct pp
{
	int x,y;
};
deque<pp>q;
bool map[105][105],marked[105][105];
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
int m,n;
int ans=0;

void bfs(int sx,int sy)//bfs 
{
    pp st;
    st.x=sx;st.y=sy;
    marked[sx][sy]=1;
    q.push_back(st);
    while(!q.empty())
    {
        pp nw=q.front();
        for(int i=0;i<4;i++)
        {
            pp nxt=nw;
            nxt.x+=dx[i];
            nxt.y+=dy[i];
            if(map[nxt.x][nxt.y]!=0 && marked[nxt.x][nxt.y]!=1)
            {
            marked[nxt.x][nxt.y]=1;//把这一连通块的点染色 
            q.push_back(nxt);}
        }
        q.pop_front();
    }
}
int main(int argc, char** argv) {
	cin>>m>>n;
	int i,j;
	char a;
	memset(map,0,sizeof(map));
	for(i=1;i<=m;i++)
	{
		for(j=1;j<=n;j++)
		{
			cin>>a;

			map[i][j]=(a!='0');
		}
	}
	for(i=1;i<=m;i++)
	{
		for(j=1;j<=n;j++)
		{
			if((!marked[i][j])&&(map[i][j]))
			{
					bfs(i,j);
					ans++; 
			}
			
		}
	}
	cout<<ans;
	return 0;
}


	

输出所有组合Cmn

#include <iostream>
#include <vector>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
vector<int>que;
bool marked[10];
int count;
void dfs(int i,int m,int n){
		int j,k;
		que.push_back(i);
		count++;
		marked[i]=true;
		if(count<m)
		{
		
			for(j=1;j<=n;j++)
			{
				if(!marked[j])
					dfs(j,m,n);
			}
		}
		else if(count==m)
		{
			for(k=0;k<que.size();k++)
			{
				printf("%d ",que[k]);
			}
			printf("\n");
		}
		
		que.pop_back();
		count--;
		marked[i]=false;
	
}


int main(int argc, char** argv) {
	
	int n,m;
	scanf("%d %d",&n,&m);
	int i;
	for(i=1;i<=n;i++)
	{
		que.clear();
		dfs(i,m,n);
	}
	return 0;

spfa

单源最短路径

#include<cstdio>
#include <cstring>
#include<iostream>
#include<algorithm>
#include <queue>
#define inf 0x3f3f3f3f
#define maxn 200025
using namespace std;

struct wayy
{
	int next,to,from,w;
}edge[maxn]; 
int head[maxn]={0};
int n,m,cnt=1;
int dist[maxn]={0},vis[maxn]={0};
struct node
{
	int index,dist;
};
queue <int> q;
void add(int u,int v,int w)
{
	edge[cnt].w=w;
	edge[cnt].to=v;
	edge[cnt].from=u;
	edge[cnt].next=head[u];
	head[u]=cnt;
	cnt++;
 } 
 
void spfa(int s,int to)
 {
 	int i,j,v;
 	for(i=0;i<=n;i++)
	 {
 		dist[i]=inf;
		vis[i]=false;	
	 }
 	dist[s]=0;vis[s]=1;
 	q.push(s);
 	while(!q.empty())
	 {
	 	v=q.front();
	 	q.pop();
	 	vis[v]=0;
	 	for(j=head[v];j;j=edge[j].next)
		 {
		 	  	int u =edge[j].to ;
		 	  	if(dist[u]>dist[v]+edge[j].w)
				   {
				   		dist[u]=dist[v]+edge[j].w;
				   		if(!vis[u])
						   {
						   		vis[u]=true;
						   		q.push(u);
						   }
				   } 
		 }
	 }
 }
 
 int main()
 {
 	int i,j,x,y,w,s,t;
 	scanf("%d%d%d%d",&n,&m,&s,&t);
 	for(i=1;i<=m;i++)
	 {
	 	scanf("%d%d%d",&x,&y,&w);
	 	add(x,y,w);
	 	add(y,x,w);
	 }
	 spfa(s,t);
	 cout<<dist[t]<<endl;
	 return 0;
	 
 }

spfa判断自环:入队次数大于入度。

floyd

非负权无环图 多源最短路径

#include <iostream>
#include <cstring> 
#include <queue>
using namespace std;
const int maxn=200+7;
const int INF = 0x3f3f3f3f;
int e[maxn][maxn]; //保存图 
int n,m;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
void floyd()
{
	int i,j,k;
	for(k=1;k<=n;k++)
	for(i=1;i<=n;i++)
	for(j=1;j<=n;j++)
	{
		if(e[i][j]>e[i][k]+e[k][j])
		{
			e[i][j]=e[i][k]+e[k][j];
		} 
	}
	
}
void findmax(){
	int mx=0;
	int i,j;
	for(i=1;i<=n;i++)
	for(j=1;j<=n;j++)
	{
		if (e[i][j] != INF) mx = max(e[i][j], mx); 
	}
	for(i=1;i<=n;i++)
	for(j=1;j<=n;j++)
	{
		if(e[i][j]==mx)
			printf("%d %d\n",i,j);
	}	
	
}
/*
	
	

*/


int main(int argc, char** argv) {
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int a,b,c,i,j;
		scanf(("%d%d"),&n,&m);
		memset(e,INF,sizeof(e));
		for(i=1;i<=n;i++)
			e[i][i]=0;
		while(m--)
		{
			scanf("%d%d%d",&a,&b,&c);
			e[a][b]=c;
		}
		floyd();
		findmax();
	
	}
	return 0;
}

最大流

ek算法


#include <cstdio>
#include <cstring>
#include <iostream>
#include<algorithm>
#include<queue>
using namespace std;

const int maxn=1007;
const int inf=0x7fffffff;

int r[maxn][maxn];
bool visit[maxn];
int pre[maxn];
int m,n;
//bfs?????,????ture
bool bfs(int s,int t){
    queue<int> q;
    int p;
    memset(visit,false,sizeof(visit));
    memset(pre,-1,sizeof(pre));
    pre[s]=s;
    q.push(s);
    visit[s]=true;
    while(!q.empty()){
        p=q.front();
        q.pop();
        //??????????1??,???????
        for(int i=1;i<=n;++i){
            if(r[p][i]>0&&!visit[i]){
                visit[i]=true;
                pre[i]=p;
                if(i==t)
                    return true;
                q.push(i);
            }
        }
    }
    return false;
}
int EK(int s,int t){
    //inc???????????
    int maxflow=0,inc;
    while(bfs(s,t)){
        //?:??????????inc?inf
        inc=inf;
        for(int i=t;i!=s;i=pre[i]){
            if(inc>r[pre[i]][i]){
                inc=r[pre[i]][i];
            }
        }
        //????????????????r????0
        for(int i=t;i!=s;i=pre[i]){

            r[pre[i]][i]-=inc;
            r[i][pre[i]]+=inc;
        }
        maxflow+=inc;
    }
    return maxflow;
}
void startEK(){
    int a,b,c;
    int ans;

    scanf("%d%d",&n,&m);
    memset(r,0,sizeof(r));
    for(int i=0;i<m;++i){
        scanf("%d%d%d",&a,&b,&c);
        r[a][b]+=c;
        //???????
        r[b][a]=c;
    }
    
    ans=EK(1,n);
    printf("%d\n",ans);
    return;
}
int main()
{
    startEK();
    return 0;
}

二分图匹配匈牙利算法

#include <iostream>
#include<cstdio>
#include <cstring>
using namespace std;
const int MAX =10000+7;
int n;
int a[MAX][MAX],used[MAX],lover[MAX];//a男生暗恋对象, lover对象是谁 
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
bool find(int x){
	int j;
	for(j=1;j<=n;j++)
	
	{
	
		if (!used[j]&&a[x][j])
		{
			used[j]=1;  //试图改变女生的归属但失败了,其他男生在遇到女生就不折腾了 
			if(lover[j]==0||find(lover[j])) //名花无主或能腾出位置 
			{
				lover[j]=x;
				return true;
			}
		
		}
	}
	return false;
}


int main(int argc, char** argv) {
	int i,x,y;
	while(~scanf("%d",&n))
	{
		int x=0;//配对成功数 
		memset(a,0,sizeof(a));
	
		memset(lover,0,sizeof(lover));
		for(i=1;i<=n;i++)
		{

			scanf("%d",&y);
			a[i][y]=a[y][i]=1; 
		}
		for(i=1;i<=n;i++)
		{
			scanf("%d",&y);
			a[y][i]=a[i][y]=1;
	}
		for(i=1;i<=n;i++)
		{
			memset(used,0,sizeof(used));
			if(find(i))
				x++;
		}
		printf("%d\n",n-x);
	}
	
	return 0;
}

计算几何

sqrt 平方根 sqr平方 atan反正切

凸包

在这里插入图片描述
在这里插入图片描述

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#define eps 1e-12
using namespace std;
const double pi= acos(-1);
int cnt;  //凸包点个数 
struct point
{
	double x,y;
	point(double _x=0,double _y=0){x=_x;y=_y;};	
}p[400010],s[400010]; 
bool operator <(const point&l,const point&r)
{
	if(l.y==r.y)return l.x<r.x;
	return l.y<r.y;
}
point operator + (const point&l,const point&r)
{
	return {l.x+r.x,l.y+r.y};
}


point operator - (const point&l,const point&r)
{
	return {l.x-r.x,l.y-r.y};
}
double cross(const point&l,const point&r)
{
	return l.x*r.y-l.y*r.x;
}
double dot(const point&l,const point&r)
{
	return l.x*r.x+l.y*r.y;
}
double length(const point&l)
{
	return sqrt(dot(l,l));
}
double dis(const point&l, const point&r)
{
	return length(r-l);
}
double cir()
{
	double ans=0;
	int i;
	for(i=1;i<=cnt;i++)
		ans+=dis(s[i],s[i+1]);
	return ans;
}
double area()
{
	double area=0;
	int i;
	for(i=2;i<cnt;i++)
	{
		area+=cross(s[i]-s[1],s[i+1]-s[1]);
	}
	return area/2;
}

double diantoxiandua(point p,point a,point b)
{
	if (a==b) return lenghth(p-a);
	vector v1=b-a,v2=p-a,v3=p-b;
	if (dot(v1,v2)<0) return length(v2);
	else if (dot(v1,v3)>0) return length(v3);
	return fabs(cross(v1,v2))/len(v1);
}
bool cmp(const point&p1,const point&p2)
{
	double tmp=cross(p1-p[1],p2-p[1]);
	if(tmp>0)return 1;
	if(tmp==0&&dis(p[0],p1)<dis(p[0],p2))
		return 1;
	return 0;
}


void graham(int n)
{
	int i;
	for(i=1;i<=n;i++)
	{
		if(p[i]<p[1])swap(p[i],p[1]);
	}
	sort(p+2,p+1+n,cmp);
	s[1]=p[1];
	cnt=1;
	for(i=2;i<=n;i++)
	{
		while(cnt>1&&cross(s[cnt]-s[cnt-1],p[i]-s[cnt])<=0)cnt--;
		cnt++;
		s[cnt]=p[i];
	}
	s[cnt+1]=p[1];
}



int main(int argc, char** argv) {

  int n,i,j; 
  cin>>n;
  double a,b,R,X,Y,th;
  cin>>a>>b>>R;
  a-=R*2;//切掉后的边长
  b-=R*2;
  double Long=sqrt(a*a+b*b)/2;//算出对角线的一半
  double An[4];//方便计算4个点的坐标
  //这个公式就不一一说明了,自己总可以推出来QAQ
  An[0]=atan(a/b);
  An[1]=pi-An[0];
  An[2]=pi+An[0];
  An[3]=2*pi-An[0];
  double ans=R*2*pi;//现在ans里放一个圆的周长
  for(i=1;i<=n*4;i+=4)
  {
    cin>>X>>Y>>th;
    for(j=0;j<4;j++)
    {//把4个点加入点集
      p[i+j].x=cos(th+An[j])*Long+X;
      p[i+j].y=sin(th+An[j])*Long+Y;
    } 
  }
  n=n*4;
	
	graham(n);
	ans+=cir();
	printf("%.2lf\n",ans);
	return 0;
}

整数格点数

int gcd(int a,int b){return b==0?a:gcd(b,a%b);}//最大公约数 
int s,b,i,n,m,p; 
int main() 
{
        freopen("fence9.in","r",stdin);
    freopen("fence9.out","w",stdout); 
        scanf("%d%d%d",&n,&m,&p);
        b=gcd(n,m)+gcd(abs(p-n),m)+p;//边上格点数目
    s=(p*m)/2;//面积 s=i+b/2-1
    i=s-b/2+1;
    printf("%d\n",i); 
    return 0;
}

fft 大数乘法


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath> 
#include<string>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

const double pi = acos (-1.0);
struct complex
{
	double x,y;
	complex(double xx=0.0,double yy=0.0)
	{
		x=xx;
		y=yy;
	}
	complex operator -(const complex &b)const
	{
		return complex(x-b.x,y-b.y);
	}
	complex operator +(const complex &b)const
	{
		return complex(x+b.x,y+b.y);
	}
	complex operator *(const complex &b)const
	{
		return complex(x*b.x-y*b.y,x*b.y+y*b.x);
	}
	
};
void change(complex y[],int len)
{
	int i,j,k;
	for(i=1,j=len/2;i<len-1;i++)
	{
		if(i<j)swap(y[i],y[j]);
		k=len/2;
		while(j>=k)
		{
			j-=k;
			k/=2;
		}
		if(j<k)j+=k;
	}
}
void fft(complex y[],int len,int on)
{
	change(y,len);
	int i, h,j,k;
	for( h=2;h<=len;h<<=1)
	{
		complex wn(cos(-on*2*pi/h),sin(-on*2*pi/h));
		for(j=0;j<len;j+=h)
		{
			complex w(1,0);
			for(k=j;k<j+h/2;k++)
			{
				complex u=y[k];
				complex t=w*y[k+h/2];
				y[k]=u+t;
				y[k+h/2]=u-t;
				w=w*wn; 
			}
		}
	} 
	if(on==-1)
		for(i=0;i<len;i++)
			y[i].x/=len;
}
const int maxn=200010;
complex x1[maxn],x2[maxn];
string str1,str2;
int sum[maxn];
int main()
{
	while(cin>>str1>>str2){
		int i,f1=1,f2=1;
		if(str1[0]=='-')
		{
			f1=-1;
			str1.erase(0,1);
		}
		if(str2[0]=='-')
		{
			f2=-1;
			str2.erase(0,1);
		}
		int len1= str1.length();
		int len2 = str2.length();
		int len=1;
		while(len<len1*2||len<len2*2)len<<=1;
		for(int i=0;i<len1;i++)
			x1[i]=complex(str1[len1-1-i]-'0',0);
		for(i=len1;i<len;i++)
			x1[i]=complex(0,0);
		for(int i=0;i<len2;i++)
			x2[i]=complex(str2[len2-1-i]-'0',0);
		for(i=len2;i<len;i++)
			x2[i]=complex(0,0);
		fft(x1,len,1);
		fft(x2,len,1);
		for(i=0;i<len;i++)
			x1[i]=x1[i]*x2[i];
		fft(x1,len,-1);
		for(i=0;i<len;i++)
			sum[i]=(int)(x1[i].x+0.5);
		for(i=0;i<len;i++)
		{
			sum[i+1]+=sum[i]/10;
			sum[i]%=10;
		} 
		len=len1+len2-1;
		while(sum[len]<=0&&len>0)len--;
		if(f1*f2==-1&&str1[0]!='0'&&str2[0]!='0')printf("-");
		for(int i=len;i>=0;i--)
			printf("%c",sum[i]+'0');
		printf("\n");
	}
	return 0;
}

在这里插入图片描述

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <math.h>
#include <stack>
#define PI acos(-1)
using namespace std;
typedef long long ll;
const int MAXN = 1e6+5;
struct complex {
    double a, b;
    complex(double aa = 0.0, double bb = 0.0) { a = aa; b = bb; }
    complex operator +(const complex &e) { return complex(a + e.a, b + e.b); }
    complex operator -(const complex &e) { return complex(a - e.a, b - e.b); }
    complex operator *(const complex &e) { return complex(a * e.a - b * e.b, a * e.b + b * e.a); }
}x1[MAXN], x2[MAXN], x[MAXN];
void change(complex *y, int len){
    int i, j, k;
    for(i=1,j=len/2; i<len-1; i++){
        if(i < j) swap(y[i], y[j]);
        k = len/2;
        while(j >= k){ j-=k; k>>=1; }
        if(j < k) j += k;
    }
}
void fft(complex *y, int len, int on){
    change(y, len);
    for(int h=2; h<=len; h<<=1){
        complex wn(cos(-on*2*PI/h), sin(-on*2*PI/h));
        for(int j=0; j<len; j+=h){
            complex w(1, 0);
            for(int k=j; k<j+h/2; k++){
                complex u = y[k], t = w*y[k+h/2];
                y[k] = u + t, y[k+h/2] = u- t, w = w*wn;
            }
        }
    }
    if(on == -1) for(int i=0; i<len; i++)  y[i].a /= len;
}
long long a[MAXN];
long long ans[MAXN];
long long M=50000;
int main()
{
    long long n;
    scanf("%lld",&n);
        memset(x1,0,sizeof(x1));
        memset(ans,0,sizeof(ans));
        long long maxn=0;
        long long zero=0;
        for(int i=0;i<n;i++)
        {
            scanf("%lld",&a[i]);
            if(!a[i]) zero++;
            x1[a[i]+M].a++;
            maxn=max(a[i]+M,maxn);
        }
        int len=1;
        while(len<2*maxn) len<<=1;
        fft(x1,len,1);
        memset(x,0,sizeof(x));
        for(int i=0;i<len;i++)
            x[i]=x1[i]*x1[i];
        fft(x,len,-1);
        for(int i=0;i<len;i++)
            ans[i]=(ll)(x[i].a+0.5);
        for(int i=0;i<n;i++)
            ans[2*(a[i]+M)]--;
        ll sum=0;
        for(int i=0;i<n;i++)
            sum+=ans[a[i]+M+M];
        sum-=2*zero*(n-1);
        printf("%lld\n",sum);
    return 0;
}

 while(T--){
        scanf("%d",&n);
        memset(num,0,sizeof(num));
        for(int i = 0;i < n;i++){
            scanf("%d",&a[i]);
            num[a[i]]++;
        }
        sort(a,a+n);
        int len1 = a[n-1]+1;
        int len = 1;
        while( len < 2*len1 )len <<= 1;
        for(int i = 0;i < len1;i++)
            x1[i] = Complex(num[i],0);
        for(int i = len1;i < len;i++)
            x1[i] = Complex(0,0);
        fft(x1,len,1);
        for(int i = 0;i < len;i++)
            x1[i] = x1[i]*x1[i];
        fft(x1,len,-1);
        for(int i = 0;i < len;i++)
            num[i] = (long long)(x1[i].r+0.5);

        len = 2*a[n-1];//为105行代码的处理优化一下界
        for(int i = 0;i < n;i++)    {num[a[i]+a[i]]--;} //减掉取两个相同的组合
        for(int i = 1;i <= len;i++) {num[i]/=2;}        //选择的无序,除以2

        sum[0] = 0;
        for(int i = 1;i <= len;i++){sum[i] = sum[i-1]+num[i];}//卷积的前缀和

        long long cnt = 0;//能够组成三角形的个数

        for(int i = 0;i < n;i++){
            cnt += sum[len]-sum[a[i]];


            cnt -= (long long)(n-1-i)*i;        //减掉一个取大,一个取小的
            cnt -= (n-1);                       //减掉一个取本身,另外一个取其它
            cnt -= (long long)(n-1-i)*(n-i-2)/2;//减掉大于它的取两个的组合
        }
        //总数
        long long tot = (long long)n*(n-1)*(n-2)/6;//答案概率的分母C(n , 3)
        printf("%.7lf\n",(double)cnt/tot);
    }
    return 0;
} 

kmp

#include <iostream>
#include<string>
#include<cstring>
using namespace std;
const int maxn = 1e6+10;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
void cal_next(char *str, int *next, int len)
{
    next[1] = 0;//next[1]初始化为0,0表示不存在相同的最大前缀和最大后缀
    int k = 0;//k初始化为0
    for (int q = 2; q <= len; q++)
    {
        while (k > 0 && str[k + 1] != str[q])//如果下一个不同,那么k就变成next[k],注意next[k]是小于k的,无论k取任何值。
        {
            k = next[k];//往前回溯
        }
        if (str[k + 1] == str[q])//如果相同,k++
        {
            k = k + 1;
        }
        next[q] = k;//这个是把算的k的值(就是相同的最大前缀和最大后缀长)赋给next[q]
    }
}
void KMP(char *str, int slen, char *ptr, int plen,int *next)
{
	
    cal_next(ptr, next, plen);//计算next数组
    int k = 0;
    for (int i = 1; i <= slen; i++)
    {
        while (k >0&& ptr[k + 1] != str[i])//ptr和str不匹配,且k>0(表示ptr和str有部分匹配)
            k = next[k];//往前回溯
        if (ptr[k + 1] == str[i])
            k = k + 1;
        if (k == plen)//说明k移动到ptr的最末端
        {
            cout << i-plen+1<< endl;
            k = 0;//重新初始化,寻找下一个
            i = i - plen + 1;//i定位到该位置,外层for循环i++可以继续找下一个(这里默认存在两个匹配字符串可以部分重叠),感谢评论中同学指出错误。
        }
    }
}
int main()
{
	char str[maxn],ptr[maxn];
	cin>>str+1>>ptr+1;
	int slen,plen;
	slen=strlen(str+1);
	plen=strlen(ptr+1);
	int *next= new int[plen];
	KMP(str,slen,ptr,plen,next);
	int i;
	for(i=1;i<=plen;i++)cout<<next[i]<<' ';
}

习惯性错误

1.注意循环中循环条件,变量的更新
2.int double 混合运算的精度问题
3.min函数一次性只能比较两个数
4.在这里插入图片描述
取模的时候每次都要取模 今后取模都请使用形如"(a+mod)%mod"的形式来代替"a%mod"
int ans=(a[r]-a[l-1]+mod)%mod; 防止出现复数
5.memset 只能设0 不能设其他值

输入

多行不定长输入

char str[maxn],ptr[maxn];
	cin>>str+1>>ptr+1;
	int slen,plen;
	slen=strlen(str+1);
	plen=strlen(ptr+1);

贪心用了冒泡排序

	for(i=1;i<=n;i++)
	{
		for(j=1;j<=n-i;j++)
		{
			if(a[j].t *a[j+1].d >a[j+1].t *a[j].d )
			{
				temp=a[j];
				a[j]=a[j+1];
				a[j+1]=temp;
			}
		}
	}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值