笔记3

生成树并查集的路径压缩

点击查看代码
//O(mlogm) sort最慢 
#include<bits/stdc++.h>
using namespace std;
int to[MAXN];//to[i] 表示 i 点在并查集里面的箭头指向谁
int go(int p){//看一下点 p 沿着并查集箭头最后会走到哪里 
	//O(1) 
	if(to[p]==p)return p;//指向自己
	/*else{
		int q=go(to[p]);
		to[p]=q;
		return q;
	}*/
	else return to[p]=go(to[p]);
} 
struct edge{
	int s,e,d;
}ed[MAXN];//ed[i] 代表第 i 条边是在 s 与 e 之间的长度为 d 的边
int n,m;
bool cmp(edge a,edge b){
	return a.d<b.d;
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++)
		cin>>ed[i].s>>ed[i].e>>ed[i].d;
	sort(ed+1,ed+m+1,cmp);//所有边按照边权进行排序
	for(int i=1;i<=n;i++)
		to[i]=i;//初始化并查集
	int ans=0;//生成树大小
	int cnt=0;//边的数量
	for(int i=1;i<=m;i++){//O(m)
		if(cnt==n-1)break;
		int p1=ed[i].s,p2=ed[i].e,d=ed[i].d;
		if(go(p1)!=go(p2)){//不在同一个连通块
			ans+=d;
			to[go(p1)]=go(p2);
			++cnt;
		}
	}
	cout<<ans<<endl;
}

SPFA

点击查看代码
#include<bits/stdc++.h>
using namespace std;
 
vector<pair<int,int> > z[500005];
int dist[500005];//dist[i] 代表从起点到 i 的最短路
bool vis[500005];//vis[i]代表 i 在不在队列里 
void add_edge(int s,int e,int d){
	z[s].push_back(make_pair(e,d)); 
}
int n,m,x;
void SPFA(int s){//以 s 作为起点算最短路 
	memset(dist,0x3f,sizeof(dist));
	dist[s]=0;
	queue<int> q;//用来存可能改变其他点最短路的点
	q.push(s);
	vis[s]=true;
	while(!q.empty()){
		int p=q.front();
		q.pop();
		vis[p]=false;
		for(int i=0;i<z[p].size();i++){
			int e=z[p][i].first;
			int d=z[p][i].second;
			if(dist[e]>dist[p]+d){
				dist[e]=dist[p]+d;
				if(!vis[e])q.push(e),vis[e]=true;
			}
		}
	} 
}
signed main(){
	cin>>n>>m>>x;
	for(int i=1;i<=m;i++){
		int s,e,d;
		cin>>s>>e>>d;
		add_edge(s,e,d);
	}
	SPFA(x);
	for(int i=1;i<=n;i++){
		cout<<dist[i]<<' ';
	}
	return 0;
}

生成树

点击查看代码
//O(nm) 
#include<bits/stdc++.h>
using namespace std;
int to[MAXN];//to[i] 表示 i 点在并查集里面的箭头指向谁
int go(int p){//看一下点 p 沿着并查集箭头最后会走到哪里 
	if(to[p]==p)return p;//指向自己
	else return go(to[p]);//递归调用 
} 
struct edge{
	int s,e,d;
}ed[MAXN];//ed[i] 代表第 i 条边是在 s 与 e 之间的长度为 d 的边
int n,m;
bool cmp(edge a,edge b){
	return a.d<b.d;
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++)
		cin>>ed[i].s>>ed[i].e>>ed[i].d;
	sort(ed+1,ed+m+1,cmp);//所有边按照边权进行排序
	for(int i=1;i<=n;i++)
		to[i]=i;//初始化并查集
	int ans=0;//生成树大小
	int cnt=0;//边的数量 
	for(int i=1;i<=m;i++){
		if(cnt==n-1)break; 
		int p1=ed[i].s,p2=ed[i].e,d=ed[i].d;
		if(go(p1)!=go(p2)){//不在同一个连通块 
			ans+=d;
			to[go(p1)]=go(p2);
			++cnt; 
		}
	}
	cout<<ans<<endl;		
} 

Bellman_ford

点击查看代码
//可以针对负数边权,但是更慢。
#include<bits/stdc++.h>
using namespace std;
int s[100005],d[1000005],e[1000005];
int n,m;
signed main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++)
		cin>>s[i]>>e[i]>>d[i];
	memset(dist,0x3f,sizeof(dist));
	dist[1]=0;
	for(int i=1;i<n;i++)
		for(int j=1;j<=m;j++)
			dist[e[j]]=min(dist[e[j]],dist[s[j]]+d[j]);
	return 0;
}

Dijkstra优化

点击查看代码
//用堆
#include<bits/stdc++.h>
using namespace std;
vector<pair<int,int> > z[100005];
int dist[100005];//dist[i] 代表从起点到 i 的最短路
bool vis[i];//vis[i]代表 i 的最短路有没有被求出来 
void add_edge(int s,int e,int d){
	z[s].push_back(make_pair(e,d)); 
}
int n,m;
void Dijkstra(int s){//以 s 作为起点算最短路 
	memset(dist,0x3f,sizeof(dist));
	dist[s]=0;
	priority_queue<pair<int,int> > heap;
	//first 用来存距离的相反数
	//second 用来存点的编号
	for(int i=1;i<=n;i++)
		heap.push(make_pair(-dist[i],i)); 
	for(int i=1;i<=n;i++){
		//选一个 dist 最小的点
		while(vis[heap.top().second])
			heap.pop();
		int p=heap.top().second;
		heap.pop();
		vis[p]=true;
		//用这个点去进行松弛操作 
		for(int j=0;j<z[p].size();j++){
			int q=z[p][j].first;
			int d=z[p][j].second;///这是一条从 p 到 q 长度为 d 的边
			if(dist[q]>dist[p]+d){
				dist[q]=dist[p+d];
				heap.push(make_pair(-dist[q],q)); 
			}
		}
	} 
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		int s,e,d;
		cin>>s>>e>>d;
		add_edge(s,e,d);
	}
	Dijkstra(1);
	int T;
	cin>>T;
	while(T--){
		int x;
		cin>>x;
		cout<<dist[x]<<'\n';
	}
	return 0;
}

拓扑排序

点击查看代码
#include <bits/stdc++.h>
using namespace std;
vector<int>a[1005];
int c[1005],b[1005],cnt,n;
signed main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		int k;
		cin>>k;
		while(k!=0)
		{
			int v=k;
			a[i].push_back(v);
			c[v]++;
			cin>>k;
		}
	}
	queue<int>q;
	for(int i=1;i<=n;i++) 
	{
	    if(c[i]==0) 
	    {
		    q.push(i);
	    }
	}
	while(q.size())
	{
		b[++cnt]=q.front();
		for(int i=0;i<a[q.front()].size();i++)
		{
			c[a[q.front()][i]]--;
			if(c[a[q.front()][i]]==0)
			{
				q.push(a[q.front()][i]);
			} 
		}
		q.pop();
	}
	if(cnt!=n)
	{
		cout<<"not topo";
		return 0;
	}
	for(int i=1;i<=n;i++) 
	{
		cout<<b[i]<<" ";
	}
	return 0;
}

多源最短路算法floyd原始版本

点击查看代码
//O(n^3) n<=250
#include<bits/stdc++.h>
using namespace std;
int dist[1005][1005][1005];
//dist[i][j][k] 代表从 j 走到 k 使得中间经过的节点编号 <=i 的情况下的最短路
const int INF=0x3f3f3f3f;
int n,m;//n 点 m 边 
signed main(){
	memset(dist,0x3f,sizeof(dist));//把数组每一个元素赋值为INF 
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int s,e,d;
		cin>>s>>e>>d;//一条从 s 到 e 长度为 d 的边
		dist[0][s][e]=min(dist[0][s][e],d); 
	} 
	for(int i=1;i<=n;i++)
		dist[0][i][i]=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			for(int k=1;k<=n;k++)
				dist[i][j][k]=min(dist[i-1][j][k],dist[i-1][j][i]+dist[i-1][i][k]);
	int T;
	cin>>T;
	while(T--){
		int i,j;
		cin>>i>>j;
		cout<<dist[n][i][j]<<'\n';
	}		
	return 0;
} 

多源最短路算法floyd压维

点击查看代码
//O(n^3) n<=250
//注意是无向图,所以存图时要存两次。
#include<bits/stdc++.h>
using namespace std;
int dist[1005][1005];
//dist[i][j][k] 代表从 j 走到 k 使得中间经过的节点编号 <=i 的情况下的最短路
const int INF=0x3f3f3f3f;
int n,m;//n 点 m 边 
signed main(){
	memset(dist,0x3f,sizeof(dist));//把数组每一个元素赋值为INF 
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int s,e,d;
		cin>>s>>e>>d;//一条从 s 到 e 长度为 d 的边
		dist[s][e]=min(dist[s][e],d); 
	} 
	for(int i=1;i<=n;i++)
		dist[i][i]=0;
		
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			for(int k=1;k<=n;k++)
				dist[j][k]=min(dist[j][k],dist[j][i]+dist[i][k]);
	int T;
	cin>>T;
	while(T--){
		int i,j;
		cin>>i>>j;
		cout<<dist[i][j]<<'\n';
	}		
	return 0;	
} 

单源最短路算法Dijkstra

点击查看代码
//选一个最短路已经求好的点,选的点一定是当前 dist 最小的点。
//进行松弛操作(用自己的最短路去更新自己周围的最短路)。
#include<bits/stdc++.h>
using namespace std;
vector<pair<int,int> > z[100005];
int dist[100005];//dist[i] 代表从起点到 i 的最短路
bool vis[i];//vis[i]代表 i 的最短路有没有被求出来 
void add_edge(int s,int e,int d){
	z[s].push_back(make_pair(e,d)); 
}
int n,m;
void Dijkstra(int s){//以 s 作为起点算最短路 
	memset(dist,0x3f,sizeof(dist));
	dist[s]=0;
	for(int i=1;i<=n;i++){
		//选一个 dist 最小的点
		int p=0;
		for(int j=1;j<=n;j++)
			if(!vis[j]&&(p==0||dist[j]<dist[p]))p=j;
		vis[p]=true;
		 
		//用这个点去进行松弛操作 
		for(int j=0;j<z[p].size();j++){
			int q=z[p][j].first;
			int d=z[p][j].second;///这是一条从 p 到 q 长度为 d 的边
			dist[q]=min(dist[q],dist[p]+d);
		}
	} 
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		int s,e,d;
		cin>>s>>e>>d;
		add_edge(s,e,d);
	}
	Dijkstra(1);
	int T;
	cin>>T;
	while(T--){
		int x;
		cin>>x;
		cout<<dist[x]<<'\n';
	}
	return 0;
}

匈牙利算法

点击查看代码
//匈牙利算法代码 
//匈牙利算法可用邻接矩阵和编表,优化用编表,不优化用邻接矩阵
//时间复杂度:O(n^3)
#include <bits/stdc++.h>
using namespace std;
bool z[maxn][maxn],vis[maxn];//z[i][j]代表左边第i个点和右边第j个点能不能匹配   vis[i]代表右边第i个点在这一轮中有没有被请求匹配过 
int n,m,k,result[maxn],ans;//n:左边有n个点,m:右边有m个点,k:中间有r条边,result[i]代表右边第i个点和左边第result[i]个点匹配 
bool dfs(int i)//让左边第i个点尝试匹配,返回是否成功 
{
	for(int j=1;j<=m;j++)//让左边的第i个点和右边第j个点尝试匹配 
	{
		if(z[i][j]&&!vis[j])
		{
			vis[j]=true;
			if(!result[j]||dfs(result[j]))
			{
				result[j]=i;
				return true;
			} 
		}
	} 
	return false;
}
signed main()
{
	cin>>n>>m>>k;
	for(int i=1;i<=k;i++)
	{
		int p1,p2;
		cin>>p1>>p2;
		z[p1][p2]=true;
	 } 
	for(int i=1;i<=n;i++)
	{
		memset(vis,false,sizeof(vis));
		if(dfs(i)) ans++;
	} 
	cout<<ans;
	return 0;
}

匈牙利算法优化

点击查看代码
//匈牙利算法优化代码 
//如需优化,要用编表
//时间复杂度:最坏是O(n*边数) 
#include <bits/stdc++.h>
using namespace std;
vector<int> z[maxn];//z[i][j]代表左边第i个点和右边第j个点能不能匹配   
bool vis[maxn];//vis[i]代表右边第i个点在这一轮中有没有被请求匹配过 
int n,m,k,result[maxn],ans;//n:左边有n个点,m:右边有m个点,k:中间有k条边,result[i]代表右边第i个点和左边第result[i]个点匹配 
void add_edge(int s,int e)
{
	z[s].push_back(e); 
}
bool dfs(int i)//让左边第i个点尝试匹配,返回是否成功 
{
	for(int k=0;k<z[i].size();k++)//让左边的第i个点和右边第j个点尝试匹配 
	{
		int j=z[i][k];
		if(!vis[j])
		{
			vis[j]=true;
		    if(!result[j]||dfs(result[j]))
			{
				result[j]=i;
				return true;
			} 
		}	
	} 
	return false;
}
signed main()
{
	cin>>n>>m>>k;
	for(int i=1;i<=k;i++)
	{
		int p1,p2;
		cin>>p1>>p2;
		add_edge(p1,p2);
	} 
	for(int i=1;i<=n;i++)
	{
		memset(vis,false,sizeof(vis));
		if(dfs(i)) ans++;
	} 
	cout<<ans;
	return 0;
}

tarjan

点击查看代码
//tarjan代码,能找出图中的强连通分量
#include<bits/stdc++.h>
using namespace std;
vector<int> z[maxn];
void add_edge(int s,int e)
{
	z[s].push_back(e); 
}
int num,n,m;;//当前已经 DFS了num个点 
int dfn[maxn];//dfn[i]第i个点是第几个被 DFS到的
int low[maxn];//low[i]代表从i点出发,沿着回边,树边or能扩大环的横叉边走能够走到的所有点中dfn最小的点(深度较小)
stack<int> s;//栈用来储存被DFS过,但还没有求出强连通分量的点 
bool instack[maxn];//instack[i]代表i是否在栈里面 
int cnt;//有几个强连通分量
int belong[maxn];//belong[i]表示i属于哪一个强连通分量 
void dfs(int i)//当前搜索到了i点
{
	num++;
	dfn[i]=low[i]=num;
	s.push(i);
	instack[i]=true; 
	for(int k=0;k<z[i].size();k++)
	{
		int j=z[i][k];
		if(!dfn[j])//这是一条树边
		{
			dfs(j);
			low[i]=min(low[i],low[j]);
		}
		else//非树边,这是一条回边or能扩大环的横叉边
		{
			if(instack[j])
			{
				low[i]=min(low[i],dfn[j]);                                         //low[i]=min(low[i],low[j]); 两种写法都可以 
			}
		}
	} 
	if(dfn[i]==low[i])
	{
		cnt++;//多了一个强连通分量
		while(s.top()!=i)
		{
			belong[s.top()]=cnt;
			instack[s.top()]=false;
			s.pop();
		} 
		s.pop();
		instack[i]=false;
		belong[i]=cnt;
	} 
} 
signed main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		int p1,p2;
		cin>>p1>>p2;
		add_edge(p1,p2);
	}
	for(int i=1;i<=n;i++)
	{
		if(!dfn[i])
		{
			dfs(i);
		}
    }
    return 0;
}

DP斐波那切数列第一种

点击查看代码
//DP斐波那切数列第一种:用别人的值来求自己,需要掌握
#include <bits/stdc++.h>
using namespace std;
int f[100010],n;
int main()
{
	cin>>n;
	f[0]=0;
	f[1]=1;
	for(int i=2;i<=n;i++)
	{
		f[i]=f[i-1]+f[i-2];
	}
	cout<<f[n]<<endl;
 } 

DP斐波那切数列第二种

点击查看代码
//DP斐波那切数列第二种:用自己的值去求别人的值,需要掌握
#include <bits/stdc++.h>
using namespace std;
int f[100010],n;
int main()
{
	cin>>n;
	f[0]=0;
	f[1]=1;
	for(int i=0;i<=n;i++)
	{
		f[i+1]+=f[i];
		f[i+2]+=f[i];
	}
	cout<<f[n]<<endl;
 } 

DP斐波那切数列第三种

点击查看代码
//DP斐波那切数列第三种:记忆化搜索,不需掌握 
#include <iostream>
using namespace std;
int n; 
bool g[100010];//bool g[i]:斐波那切数列第i项有没有求出来 
int f[100010];//int f[i]:斐波那切数列第i项的值
int dfs(int n)//求斐波那切数列第n项的值 
{
	if(n==0)
	{
		return 0;
	}
	if(n==1)
	{
		return 1;
	}
	if(g[n])
	{
		return f[n];
	}
	g[n]=true;
	return f[n];
}
int main()
{
	cin>>n;
	cout<<dfs(n)<<endl;
	return 0;
 } 

原始排列DP

点击查看代码
//排列DP原始代码
//O(n^4)  
#include<bits/stdc++.h>
using namespace std;
int f[maxn][maxn];//f[i][j] i代表插入到哪个数
int n;
int main()
{
    cin>>n;
    f[1][0]=1;
    for(itn i=1;i<n;i++)
    {
        for(int j=0;j<i*(i-1)/2;j++)//n个数最多形成 n*(n-1)/2 个逆序对
        {
            for(int k=0;k<=i;k++)
            {
                //i+1要插入到第k个位置
                f[i+1][j+i-k]+=f[i][j]; 
            } 
        }
    }
    int ans=0;
    for(int i=0;i<=n*(n-1)/2;i+=2)
    {
        ans+=f[n][i];
    }
    cout<<ans;
    return 0;
}

排列DP优化代码

点击查看代码
//O(n^2)  
#include<bits/stdc++.h>
using namespace std;
int f[maxn][maxn];//j=0 偶数个  j=1 奇数个 
int n;
int main()
{
    cin>>n;
    f[1][0]=1;
    for(itn i=1;i<n;i++)
    {
        for(int j=0;j<2;j++)//n个数最多形成 n*(n-1)/2 个逆序对
        {
            for(int k=0;k<=i;k++)
            {
                //i+1要插入到第k个位置
                f[i+1][(j+i-k)%2]+=f[i][j]; 
            } 
        }
    }
    int ans=f[n][0];
    cout<<ans;
    return 0;
}

求子序列代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n;
int a[maxn];
int f[maxn];
//最后一个选的数是a[i]的情况下最多能选几个数  
int g[maxn];  
//g[i]代表 状态f[i] 是由状态 f[g[i]] 转移过来的 
void print(int p)
{ 
    //输出当前最后一个数是a[p]的那组解 
    if(!p) return;
    print(g[p]);
    cout<<a[p]<<' ';
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    for(int i=1;i<=n;i++)
    {
        //求f[i] 
        for(int j=1;j<i;j++)
        {
            //倒数第2个数是a[j]
            if(a[j]<a[i])
            {
                if(f[j]>f[i])
                {
                    f[i]=f[j];
                    g[i]=j;
                }
            }
        }
        f[i]++;
    }
    int p=1;
    for(int i=2;i<=n;i++)
    {
        if(f[i]>f[p])
        {
            p=i;
        }
    }
    cout<<f[p]<<endl;
    print(p);
    return 0;
}

求最优解方案数答案

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n;
int a[maxn];
int f[maxn];
//最后一个选的数是a[i]的情况下最多能选几个数  
int g[maxn];  
//g[i]代表 状态f[i] 是由状态 f[g[i]] 转移过来的 
int h[maxn];
//h[i]代表 状态f[i] 有多少种最优解 
void print(int p)
{ 
    //输出当前最后一个数是a[p]的那组解 
    if(!p) return;
    print(g[p]);
    cout<<a[p]<<' ';
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    for(int i=1;i<=n;i++)
    {
        h[i]=1;
    }
    for(int i=1;i<=n;i++)
    {
        //求f[i] 
        for(int j=1;j<i;j++)
        {
            //倒数第2个数是a[j]
            if(a[j]<a[i])
            {
                if(f[j]>f[i])
                {
                    f[i]=f[j];
                    g[i]=j;
                    h[i]=h[j];
                }
                else if(f[j]==f[i])
                {
                    h[i]+=h[j];
                    //都是最优解 
                }
            }
        }
        f[i]++;
    }
    int p=1;
    for(int i=2;i<=n;i++)
    {
        if(f[i]>f[p])
        {
            p=i;
        }
    }
    cout<<f[p]<<endl;
    print(p);
    cout<<endl;
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        if(f[i]==f[p]) ans++;
    }
    cout<<ans<<endl;
    return 0;
}

01背包DP代码

点击查看代码
//01背包DP代码 
//时间复杂度:O(nm)=O(物品数量*体积最大值) 
#include <bits/stdc++.h>
using namespace std;
int f[1000][1000],n,m,v[1000],w[1000];//f[i][j]代表前i个物品已经考虑完,用掉了j的体积所能获得的最大价值 
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>v[i]>>w[i];//读入体积和价值 
	} 
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<=m;j++)//考虑第i个物品选不选 
		{
			f[i+1][j]=max(f[i+1][j],f[i][j]);//第i+1个物品不选 
			f[i+1][j+v[i+1]]=max(f[i+1][j+v[i+1]],f[i][j]+w[i+1]);//第i+1个物品选 
		}
	}
	int ans=0;
	for(int i=0;i<=m;i++)
	{
		ans=max(ans,f[n][i]);
    } 
	cout<<ans<<endl;//cout<<f[n][m]<<endl;
	return 0;
} 

无穷背包DP代码原始版本

点击查看代码
//无穷背包问题原始版本代码
//时间复杂度:O(nm^2) 
#include <bits/stdc++.h>
using namespace std;
int f[1000][1000],n,m,v[1000],w[1000];//f[i][j]代表前i个物品已经考虑完,用掉了j的体积所能获得的最大价值 
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>v[i]>>w[i];//读入体积和价值 
	} 
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<=m;j++)//要求状态f[i][j]用别人来求自己的值 
		{
			for(int k=0;k*v[i]<=j;k++)//第i个物品选k个 
		    {
		    	f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]); 
			}
		}
	}
	int ans=0;
	for(int i=0;i<=m;i++)
	{
		ans=max(ans,f[n][i]);
    } 
	cout<<ans<<endl;//cout<<f[n][m]<<endl;
	return 0;
} 

无穷背包DP代码优化

点击查看代码
//无穷背包问题优化代码 
//时间复杂度:O(nm) 
#include <bits/stdc++.h>
using namespace std;
int f[1000][1000],n,m,v[1000],w[1000];//f[i][j]代表前i个物品已经考虑完,用掉了j的体积所能获得的最大价值 
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>v[i]>>w[i];//读入体积和价值 
	} 
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<=m;j++)//要求状态f[i][j]用别人来求自己的值 
		{
			f[i][j]=f[i-1][j];//上 
			if(j>=v[i])
			{
				f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);//左 
			}
		}
	}
	int ans=0;
	for(int i=0;i<=m;i++)
	{
		ans=max(ans,f[n][i]);
    } 
	cout<<ans<<endl;//cout<<f[n][m]<<endl;
	return 0;
} 

判断二分图

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=100010;
//vector存图:边表
//缺点:取i->j这条边的信息只需要O(n) 
//优点:只需要O(n+m)的内存 
vector<int> g[maxn];//g[i] 用来存储所有从i出发的边 
void add_edge(int s,int e)//添加一条从s -> e
{
	g[s].push_back(e);
}
int col[maxn],n,m;
//col[i]==0 i点还没决定放哪边
//col[i]==1 i点放左边
//col[i]==2 i点放右边 
signed main()
{
	cin >>n >> m;
	for (int i=1;i<=m;i++)
	{
		int s,e;
		cin >> s >> e;
		add_edge(s,e);
		add_edge(e,s);
	}
	bool able=true;
	for (int i=1;i<=n;i++)
	{
		if (col[i] == 0)
		{
			col[i] = 1;
			queue<int> q;//还需要更新周围点放哪边的那些点 
			q.push(i); 
			while (q.size())
			{
				int now=q.front();
				q.pop();
				for (int i=0;i<g[now].size();i++)
				{
					int j=g[now][i];//是一条从now -> j的边
					if (col[j] == 0) //j点还没有放
					{
						col[j] = 3-col[now];
						q.push(j);
					}
					else if (col[now] == col[j]) 
					{
						able=false;
					}
				}
			} 
		}
	}
	if (able)
	{
		cout << "yes\n";
	} 
	else 
	{
		cout << "no\n";
	}
	return 0;
}

KMP代码

点击查看代码
#include <bits/stdc++.h>
using namespace std;
// 求 字符串 s 的 next 数组 
void calc_next(string s, int nxt[])
{
	int n = s.length();
	nxt[0] = -1;
	nxt[1] = 0;
	for (int k = 1; k < n; ++k) 
	{
		// 计算 nxt[k+1] 
		int p = nxt[k];
		while (p)
		{
			if (s[p] == s[k])
			{
				break;
			} 
			else 
			{
				p = nxt[p];
			}
		}
		nxt[k+1] = p + (s[p] == s[k]);
//		printf("%d %d\n", k+1, nxt[k+1]);
	}
}
int nxt_t_concat_s[2000010],nxt_t[1000010];
signed main()
{
	string s, t;
	cin >> s >> t;
	calc_next(t + "#" + s, nxt_t_concat_s);
	int m = t.length(), n = s.length();
	for (int i = m+2; i <= n+m+1; ++i) 
	{
		if (nxt_t_concat_s[i] == m)
			printf("%d\n", i-m-m);
	}
	calc_next(t, nxt_t);
	for (int i = 1; i <= t.length(); ++i)
		printf("%d ", nxt_t[i]);
	printf("\n");
	return 0;
}
posted @ 2023-10-02 08:44  zhuyucheng  阅读(63)  评论(1)    收藏  举报