假期集训(3)简单图论随记

1.floyd(最短路)
读入时注意筛选最小边

void floyd()
{
	for(int u=0;u<=n;u++)
	 for(int i=0;i<=n;i++)
	  for(int j=0;j<=n;j++)
	   dp[i][j]=min(dp[i][j],dp[i][u]+dp[u][j]);
}

2.dijkstra(最短路)
函数调用前记得初始化
核心思想是从起点发散,每次找到下一个任意未标记点的最短路
如A——>C为4,A——>B为2,则选取A——>B这条路径,并将B点标记,更新路径,再从B点发散寻找下一点

int dis[maxn];
int vis[maxn];
int a[maxn][maxn];

void dij(int start)
{
	for(int i=1;i<=n;i++)
		dis[i]=a[start][i];
	vis[s]=1;
	for(int i=1;i<=n;i++)
	{
		int k=0;//k取一个无法到达值
		for(int j=1;i<=n;j++)
		 if(vis[j]==0&&(k==0||dis[k]>dis[j])
		  k=j;
		for(int j=1;j<=n;j++)
	  	 if(vis[j]==0&&dis[j]>dis[k]+a[k][j])
		  dis[j]=dis[k]+a[k][j];
	}
}

3.dijkstra的队列优化写法

vector是从0开始的

struct node
{
    ll  to,value;
    node(ll to1,ll value1):to(to1),value(value1){}//数据读入
    friend bool operator<(node a, node b)
    {
        return a.value>b.value;
    }
};

vector<node> v[maxn];//v[i]的i记录起点,v[i].to记录终点;
ll dis[maxn];//记录最短路
priority_queue <node> que;

void dij(ll s)//起点
{
    while(!que.empty()) que.pop();//初始化
    for(int i=0;i<=n;i++)
    {
        dis[i]=inf;
    }
    dis[s]=0;//初始化
    que.push(node(s,0));//将起点送入优先队列
    while(!que.empty())
    {
        node tmp=que.top();
        que.pop();
        if(tmp.value > dis[tmp.to]) continue;
        for(ll i=0;i<(ll) v[tmp.to].size();i++)
        {
            ll to=v[tmp.to][i].to;
            ll val=v[tmp.to][i].value;
            if(dis[to]>dis[tmp.to]+val)
            {
                dis[to]=dis[tmp.to]+val;
                que.push(node(to,dis[to]));
            }
        }
    }
}

4.spfa

5.链式前向星(对边的记录)
初始化时head要赋值为-1

struct Edge
{
    int to,w,next;
}E[maxn];

int head[maxn];
int tot;

inline void addEdge(int u,int v,int w)
{
    Edge[tot].to=v;
    Edge[tot].w=w;
    Edge[tot].next=head[u];
    head[u]=tot++;
}
void solve(int x)
{
	for(int i=head[x];~i;i=E[i].next)//i=-1时结束循环
	//something...
}

6.最小生成树(prime)
和dijkstra非常像,只有一个判断语句不同,dij要保证每个点和单源点相连,而prime只要保证连通且当前路径最小即可

struct node
{
    int to;
    int val;
};

vector<node> e[maxn];

int dis[maxn];
int vis[maxn];

int prime(int n)
{
    memset(vis,0,sizeof(vis));
    int ans=0;
    dis[1]=0;
    vis[1]=1;
    for(int i=0;i<e[1].size();i++)
    {
        dis[e[1][i].to]=e[1][i].val;
    }
    for(int point=2;point<=n;point++)
    {
        int minn=inf;
        int k=0;
        for(int i=1;i<=n;i++)
        {
            if(vis[i]==0&&minn>dis[i])
            {
                minn=dis[i];
                k=i;
            }
        }
        vis[k]=1;
        ans+=minn;
        for(int i=0;i<e[k].size();i++)
        {
            if(dis[e[k][i].to]>e[k][i].val)
            {
                dis[e[k][i].to]=e[k][i].val;
            }
        }
    }
    return ans;
}

7.并查集

int root[maxn];
int FIND(int x)
{
	return root[x]==x?x:root[x]=FIND(root[x]);	
}

void hb(int x,int y)//合并
{
	int xx=FIND(x);
	int yy=FIND(y);
	if(xx!=yy)
	{
		root[xx]=yy;
	}
}

8.最小生成树(kruskal)
使用时要在先对对边进行排序

int root[maxn];
int FIND(int x)
{
	return root[x]==x?x:root[x]=FIND[x];	
}

struct Edge
{
	int x,y,w;
	friend bool operator<(Edge a,Edge b)
	{
		return a.w<b.w;
	}
}e[maxn];

int  kruskal()
{
	int ans=0;
	for(int i=1;i<=n;i++)
		root[i]=i;
	for(int i=1;i<=m;i++)
	{	
		int a=FIND(e[i].x),b=FIND(e[i].y);
		if(a!=b)
		{
			root[a]=b;
			ans+=e[i].w;
		}	
	}
	return ans;
}

8.欧拉通路、回路

9.二分图染色判断

int vis[maxn];
int head[maxn];
int color[maxn];//使用^运算 0未染色,2为一种颜色,3为另外一种颜色
/*
也可 1为黑,2为白 用3-color来使颜色交替变换
*/
int tot;

struct node
{
    int to,next;
}E[maxn];

void adde(int x,int y)
{
    E[tot].to=y;
    E[tot].next=head[x];
    head[x]=tot++;
}

void add(int x,int y)
{
    adde(x,y);
    adde(y,x);
}

void init()
{
    memset(vis,0,sizeof(vis));
    memset(head,-1,sizeof(head));
    tot=0;
    memset(color,0,sizeof(color));
}

bool dfs(int past,int y)
{
    color[past]=y;
    for(int i=head[past];~i;i=E[i].next)
    {
        int now=E[i].to;//now 为past的邻接点
        if(color[past]==color[now])//判断past和now染色是否相同
            return false;
        if(color[now]==0&&!dfs(now,y^1))//past的邻接点未染色,则进行递归,直到对应的点完成染色
            return false;
    }
    return true;//表示没有搜索到有冲突的颜色节点,二分图成立
}

bool jungle()//judge
{
    for(int i=1;i<=n;i++)
    {
        if(color[i]==0)//确保所有点完成遍历染色(可能有多个连通图)
        /*
        	如hdu4751,建边是对互相不认识的人建边,当所有人都认识的时候没有边,此时每个图仅有一个点,
        	需要做的就是对每个点(连通图)染色
		*/
         if(dfs(i,2)==false)
        {
            return false
        }
    }
    return true;
}

10.二分图最大匹配(匈牙利算法)

int vis[maxn];
int head[maxn];
int match[maxn];//match[i]=j i与j对应匹配,i为右边被匹配点
int tot;

struct node
{
    int to,next;
}E[maxn];

void adde(int x,int y)
{
    E[tot].to=y;
    E[tot].next=head[x];
    head[x]=tot++;
}

void add(int x,int y)
{
    adde(x,y);
    adde(y,x);
}

bool dfs(int x,int ti) //ti记录次数
{
    if(vis[x]==ti) return false;
    vis[x]=ti;
    for(int i=head[x];~i;i=E[i].next)
    {
        int tmp=E[i].to;
        if(match[tmp]==0||dfs(match[tmp],ti))
        /*
        tmp点未匹配时候,tmp点与当前点匹配
        tmp点已经匹配,找到之前匹配点,对其进行再匹配处理,若能成功,则将tmp点与当前点匹配
        */
        {
            match[tmp]=x;
            return true;
        }
    }
    return false;
}

int solve()
{
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        if(dfs(i,i)) ans++;
    }
    return ans;
}

void init()
{
    memset(vis,0,sizeof(vis));
    memset(head,-1,sizeof(head));
    tot=0;
    memset(color,0,sizeof(match));
}

11.拓扑排序
https://blog.csdn.net/qq_41713256/article/details/80805338

while(!q.empty())
    {
        int tmp=q.front();
        q.pop();
        int len=v[tmp].size();
        for(int i=0;i<len;i++)
        {
            if(--degree[v[tmp][i]]==0)
            {
                q.push(v[tmp][i]);
            }
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值