一些实用的模板

1°FLOYD判最小环

注:划线部分为基本的FLOYD算法。最好写的单源最短路径算法。但时间复杂度O(n^3),n=1000基本就用不了了。。。

void floyd(){
        int MinCost = inf;
        for(int k=1;k<=n;k++){
            for(int i=1;i<k;i++)
                for(int j=i+1;j<k;j++)
                    MinCost = min(MinCost,dis[i][j]+mp[i][k]+mp[k][j]);//更新k点之前枚举ij求经过ijk的最小环
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);      //更新k点
        }
        if(MinCost==inf)puts("It's impossible.");
        else printf("%d\n",MinCost);
    }

2°SPFA算法:单源最短路径算法

基本思路:将起点放入队列,每次取出队首元素,对其所有邻边进行松弛操作,并放入队列(若队列里已有该元素则无需重复添加,但若此时队列里没有该元素即使先前已进行过计算仍需放入队列不断更新

优点:速度快,可处理权值为负的图

缺点:可能会被一些恶心的数据卡掉。。。

void spfa(int s){
	for(int i=0; i<=n; i++) dis[i]=99999999; //初始化每点i到s的距离
	dis[s]=0; vis[s]=1; q[1]=s;  队列初始化,s为起点
	int i, v, head=0, tail=1;
	while (head<tail){   队列非空
		head++; 
		v=q[head];  取队首元素
		vis[v]=0;   释放队首结点,因为这节点可能下次用来松弛其它节点,重新入队
		for(i=0; i<=n; i++)  对所有顶点
		   if (a[v][i]>0 && dis[i]>dis[v]+a[v][i]){  
				dis[i] = dis[v]+a[v][i];   修改最短路
				if (vis[i]==0){  如果扩展结点i不在队列中,入队
					tail++;
					q[tail]=i;
					vis[i]=1;
				}
		   }
		
	}
}

Dijkstra(迪杰斯特拉)算法:单源最短路径算法

基本思路:每次确定到起点距离最短且距离尚未确定的点的dis,并对其所有邻边进行松弛操作

优点:非常常用!不容易被卡

缺点:慢(但相比FLOYD还是快的(雾 不加优化O(n^2)

void dijkstra()
{
    for(int i=1;i<=N;i++) dist[i]=(i==1)?0:INF;
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=N;i++)
    {
        int mark=-1,mindis=INF;
        for(int j=1;j<=N;j++)
        {
            if(!vis[j]&&dist[j]<mindis)
            {
                mindis=dist[j];
                mark=j;
            }
        }
        vis[mark]=1;
        for(int j=1;j<=N;j++) if(!vis[j]) dist[j]=min(dist[j],dist[mark]+g[mark][j]);
    }
}

4°匈牙利算法:二分图匹配(也可以用最大流求解,但这个似乎更好写一点)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=505;
int line[N][N];
int girl[N],used[N];
int k,m,n;
bool found(int x)
{
    for(int i=1; i<=n; i++)
    {
        if(line[x][i]&&!used[i])
        {
            used[i]=1;
            if(girl[i]==0||found(girl[i]))
            {
                girl[i]=x;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    int x,y;
    while(scanf("%d",&k)&&k)
    {
        scanf("%d %d",&m,&n);
        memset(line,0,sizeof(line));
        memset(girl,0,sizeof(girl));
        for(int i=0; i<k; i++)
        {
            scanf("%d %d",&x,&y);
            line[x][y]=1;
        }
        int sum=0;
        for(int i=1; i<=m; i++)
        {
            memset(used,0,sizeof(used));
            if(found(i)) sum++;
        }
        printf("%d\n",sum);
    }
    return 0;
}

*转自博客算法讲解:二分图匹配 强推一波,讲解浅显易懂而且十分有趣233

5°最大流EK算法

这个是自己手打的啊。。。码风实在不堪入目

bool flag=true;
while(flag){
	flag=false;
	queue<int> q;
	memset(vis,false,sizeof(vis));
	q.push(0);
	vis[0]=true;
	memset(p,-1,sizeof(p));
	while (!q.empty()) {
	    int node=q.front();
    	    q.pop();
	    if (node==n) {
		flag=true;
		break;
	    }
	    for (int i=1;i<=n;i++) if (!vis[i]&&c[node][i]>f[node][i]) {
		q.push(i);
		vis[i]=true;
		p[i]=node;
	    }
        }
	if (!flag) break;
	int tmp=1e+7;
	for (int i=n;p[i]!=-1;i=p[i]) 
	    tmp=min(tmp,c[p[i]][i]-f[p[i]][i]);
	for (int i=n;p[i]!=-1;i=p[i]) {
		f[p[i]][i]+=tmp;
		c[i][p[i]]+=tmp;
	}
}
int ans=0;
for (int i=1;i<=n+m+1;i++) ans+=f[0][i];

猜你喜欢

转载自blog.csdn.net/qq_42158832/article/details/80629379
今日推荐