zoukankan      html  css  js  c++  java
  • 图论常见解题方法和套路

    一、最短路径问题

    1. 多源最短路径
      Floyd:
    void Floyd(int *d)
    {
          for(int k = 1; k <= n; ++ k)
                for(int i = 1; i <= n; ++ i)
    	            for(int j = 1; j <= n; ++ j)
                        {
    			    d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
                        }
          return;
    }
    

    请记住此五行代码。
    一般而言,可以用它判断图两点间的联通情况,称之为传递闭包,此时,仅需将转移的那一行改为:(d[i][j]|=d[i][k]&d[k][j];)

    • 最小环问题(好好看看啊)
    1. 单源最短路径
      以下示均使用邻接表。
      Dijkstra:
    void Dijkstra(int S)
    {
    	priority_queue <pii> Q;
      
    	while(!Q.empty()) Q.pop();
            memset(dis, 0x7f, sizeof(dis);
            memset(vis, false, sizeof(vis));
    	Q.push(make_pair(0, S));
    	dis[S] = 0;
    	while(!Q.empty())
    	{
    		int u = Q.top().second;Q.pop();	
    		if(vis[u]) continue;
    		vis[u] = true;
    		for(int i = 0; i < G[u].size(); ++ i)
    		{
    			int v = G[u][i];
    			if(dis[v] > dis[u] + W[u][i])
    			{
    				dis[v] = dis[u] + W[u][i];
    				Q.push(make_pair(-dis[v], v));
    			}
    		}
    	}
    	return;
    }
    

    spfa:

    void SPFA(int S)
    {
    	queue <int> Q;
    	while(!Q.empty()) Q.pop();
    	memset(inq, false, sizeof(inq));
    	memset(dis, 0x7f, sizeof(dis));
            Q.push(S);
            inq[S] = true;
    	dis[S] = 0;
    
    	while(!Q.empty())
    	{
    		int u = Q.front();
    		Q.pop();
    		inq[u] = false;
    		for(int i = 0; i < G[u].size(); ++ i)
    		{
    			int v = G[u][i], w = W[u][i];
    			if(dis[v] > dis[u] + w)
    			{
    				dis[v] = dis[u] + w;
    				if(!inq[v])
    			        {
    					inq[v] = 1;
    					Q.push(v);
    				}
    			}
    		}
    	}
    	return;
    }
    
    • 若要求得从源点到终点所有路径,能够经过的边权最小的权值时,应将(dis[v] = dis[u] + w)改为(dis[v] = min(w, dis[u])),而求最大值的时候,在Dijkstra还需要把堆写成大根堆;
    • 当判断与源点相连是否存在负环的情况时,应当使用SPFA,在进行松弛操作的基础上加上一句话:(cnt[v] = cnt[u] + 1),其中(cnt[i])指的是源点到节点i最短路径边的条数,则若(cnt[v] ≥ n),那么就判定为负环;
    • 通常情况下,如果求每个节点到源点的最短路时,须要考虑建反图,跑一遍最短路即可;若记录最短路的条数时,应当更新(或松弛)的时候累加;
    • 通常情况下,最短路更可能结合拓扑排序,请留意!

    二、并查集

    既能合并,又能查询的图论神器。
    两种方法中,在图论中首选启发式合并。

    //查询
    int get(int x)
    {
          if(fa[x] == x) return x;
          return get(fa[x]);
    }
    
    //合并
    void merge(int x, int y)
    {
          if(dep[x] < dep[y]) swap(x, y);
          int v = get(y);
          fa[v] = x;
          dep[x] += dep[y];
          return;
    }
    

    主要用于存在多个联通块的情况。
    此结构非常精巧,一定格外留意。

    三、拓扑排序

    不得不说,如果学图论时没有熟练掌握该操作,将是非常的遗憾。
    代码如下:

    void topsort() {
    	while(!Q.empty()) 
          {
                Q.pop();
          }
    	
    	for(int i = 1; i <= n; ++i) {
    		if(deg[i] == 0) {
    			Q.push(i);
    		}
    	}
    	while(!Q.empty()){
    		int x = Q.front();a.push_back(x);
    		Q.pop();
    		for(int i = 0; i < G[x].size(); ++ i){
    			int y = G[x][i];
    			--deg[y];
    			if(deg[y] == 0){
    				Q.push(y);
    			}
    		}
    	}
    	return;
    }
    

    拓扑排序用于判环、找结点的拓扑序等等。

  • 相关阅读:
    How to convert VirtualBox vdi to KVM qcow2
    (OK)(OK) adb -s emulator-5554 shell
    (OK)(OK) using adb with a NAT'ed VM
    (OK) How to access a NAT guest from host with VirtualBox
    (OK) Creating manually one VMs from an existing VDI file in CLI (VBoxManage) in Fedora 23
    (OK)(OK) Creating VMs from an existing VDI file in CLI (VBoxManage) in Fedora 23
    (OK) Creating_VMs_from_an_existing_VDI_file.txt
    (OK) Creating VMs from an existing VDI file —— in OS X
    (OK) install_IBM_SERVER.txt
    (OK) install chrome & busybox in android-x86_64 —— uninstall chrome
  • 原文地址:https://www.cnblogs.com/zach20040914/p/13373077.html
Copyright © 2011-2022 走看看