zoukankan      html  css  js  c++  java
  • 图论板子

    好多板子都没打啊...

    快读

    哪都说不定要用的对不...

    inline int read()
    {
    	int x=0; bool flag=1; char ch=getchar();
    	while(ch<'0'||ch>'9') 
    	{
    		if(ch=='-') 
    			flag=0; 
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9') 
    	{
    		x=(x<<1)+(x<<3)+ch-'0';
            // x=(x<<1)%mod+(x<<3)%mod+ch-'0'; 就是带模快读
    		ch=getchar();
    	}
    	if(flag) 
    		return x;//x%mod
    	return -x;//-x%mod
    }
    

    最短路

    dij

    struct node
    {
        int link;
        long long w;
        bool operator < (const node &qq) const{
            return qq.w<w;
        }
    };
    vector <node> f[N];
    priority_queue <node> q;
    void dij(int s)
    {
        while(!q.empty())
            q.pop();
        for(int i=1;i<=n;i++)
            dis[i]=inf;
        dis[s]=0;
        q.push((node){s,0});
        while(!q.empty())
        {  
            node temp=q.top();
            q.pop();
            if(use[temp.link])
                continue;
            use[temp.link] = 1;
            for(auto i:f[temp.link])
            {
                if(dis[i.link]>=dis[temp.link]+i.w)
                {
                    dis[i.link] = dis[temp.link] + i.w;
                    q.push((node){i.link, dis[i.link]});
                }
            }
    
        }
    }
    

    spfa

    void spfa(int s)
    {
        memset(use,0,sizeof(use));
        memset(dis,0x7f,sizeof(dis));
        use[s]=1;
        dis[s]=0;
        q.push((node){s,0});
         while(!q.empty())
        {
            node temp=q.front();
            q.pop();
            use[temp.link]=0;
            for(int i=0;i<f[temp.link].size();i++)
            {
                node xx=f[temp.link][i];
                if(dis[xx.link]>dis[temp.link]+xx.w)
                {
                    dis[xx.link]=dis[temp.link]+xx.w;
                    if(!use[xx.link])
                    {
                        q.push((node){xx.link,dis[xx.link]});
                        use[xx.link]=1;
                    }
                }
            }
        }
    }
    

    spfa可以跑负权,但是dijstar不行,都可以跑最长路找环(除了跑有负权的边以外别用spfa了)

    拓扑排序

    void top()
    {
        while(!q.empty())
        {  
            int temp=q.front();
            q.pop();
            for(auto i:f[temp])
            {
                d[i]--;
                /*code*/
                if(d[i]==0)
                    q.push(i);
            }
        }
    }
    

    拓扑排序也可以找最短路|最长路(有人又花里胡哨把这叫dp)就在code里加dis[i]=min(...)就完事了

    和dijkstar本质就是只能DAG里面找吧,并且只能从入度为0的点为起点,优点就是可以同时找多条起点和终点的dis(从这个答案角度来说,叫dp似乎也没问题)虽然dijkstar建超级起点和汇点也行比较拓扑本职工作也不是干这的,别要求太多了

    在有向无环图中可以拓扑排序来找到一个拓扑序列,拓扑排序也可以找环

    由于拓扑排序每次都是从入度为0的点开始,而环上的点的入度都不会为0,所以环上的点就不会参加排序,也就是说,经过拓扑排序后剩下的边和点构成的都是环(入读不为零的点)

    倍增LCA

    
    fa[N][30],deep[N]
    vector <int> f[N];
    void dfs(int x)
    {
    	for(int i=1;i<=25;i++)
    	{
    		if(deep[x]<(1<<i))
    			break;
    		fa[x][i]=fa[fa[x][i-1]][i-1];
    	}
    	for(int i=0;i<f[x].size();i++)
    	{
    		int temp=f[x][i];
    		if(temp!=fa[x][0])
    		{
    			fa[temp][0]=x;
    			deep[temp]=deep[x]+1;
    			dfs(temp);
    		}
    	}
    }
    int lca(int x,int y)
    {
    	if(deep[x]<deep[y])
    		swap(x,y);
    	int t=deep[x]-deep[y];
    	for(int i=0;i<=25;i++)
    	{
    		if(t&(1<<i))
    			x=fa[x][i];
    	}
    	if(x==y)
    		return x;
    	for(int i=25;i>=0;i--)
    	{
    		if(fa[x][i]!=fa[y][i])
    		{
    			x=fa[x][i];
    			y=fa[y][i];
    		}
    	}
    	return fa[x][0];
    }
    

    并查集

    也可以找环....tarjan也是用并查集来维护找出的强连通分量(能找环的太多了...)

    int fa[N],ha[N],cnt;
    long long w[N],sum[N];
    int find(int x)
    {
    	//if(x==fa[x])
    	//	return x;
    	//return fa[x]=find(fa[x]);
        // 最后return 应该是return find(fa[x]) 不然有些题是过不了的(还是说本来就是错误的)
        return fa[x]==x?fa[x]:find(fa[x]);//等价该过的写法(我居然三年都没发现问题!!!)
    }
    void merge(int a,int b)
    {
    	int r1=find(ha[a]),r2=find(fa[ha[b]]);
    	if(r1!=r2)
    	{
    		fa[r1]=r2;
    		w[r2]+=w[r1];
    		sum[r2]+=sum[r1];
    	}
    }
    void move(int a,int b)
    {
    	// 把a移动到b集合 
    	int r1=find(ha[a]),r2=find(ha[b]);
    	if(r1!=r2)
    	{
    		w[r1]-=a;
    		sum[r1]-=1;
    		w[r2]+=a;
    		sum[r2]+=1;
    		ha[a]=++cnt; //先把a移出再定向father
    		// 虽然之前的ha[a]还在集合里,但是之后再也不会用到,并且权值该减掉的全部减掉了所以相当于删除操作 
    		fa[ha[a]]=r2;
    	}
    } 
    int main()
    

    强连通

    缩点

    void tarjan(int x)
    {
    	dfn[x]=low[x]=++tot;
    	use[x]=1;
    	s.push(x);
    	for(int i=0;i<f[x].size();i++)
    	{
    		int temp=f[x][i];
    		if(use[temp]==0)
    		{
    			tarjan(temp);
    			low[x]=min(low[x],low[temp]);
    		}
    		else
    		{
    			if(use[temp]==1)
    				low[x]=min(low[x],dfn[temp]);
    		}
    	}
    	if(low[x]==dfn[x])//类似并查集合并
    	{
    		sum++;
    		while(!s.empty())
    		{
    			int temp=s.top();
    			s.pop();
    			use[temp]=0;
    			be[temp]=sum;//sum是最后缩点后的点个数
    			sumv[sum]+=w[temp];//权值该干嘛干嘛
    			if(x==temp)
    				return ;
    		}
    	}
    }
    

    割点

    int tim,dfn[N],low[N];
    bool use[N];//是否是割点
    vector<int> f[N];
    void tarjan(int x,int fa)//求割点
    {
        dfn[x] = low[x] = ++tim;
        int child = 0;
        for (auto i:f[x])
        {
            if(dfn[i]==0)
            {
                tarjan(i,fa);
                low[x] = min(low[x], low[i]);
                if (low[i]>=dfn[x]&&x!=fa)//非根节点并且子节点low都大于dfn[x]说明是割点(
                    use[x] = 1;
                if(x==fa)
                    child++;
            }
            low[x] = min(low[x], dfn[i]);//这里与缩点不同
        }
        if(child>=2&&x==fa)//根节点且有两个子树为割点
        {
            use[x]=1;
        }
    }
    

    网络流

    dinic

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 5e3+5,inf=0x3f3f3f3f;
    int n, m, s, t, x, y, z;
    int level[N];
    struct node
    {
        int link;
        int w;
        int position;
    };
    vector<node> f[N];
    queue<int> q;
    int dfs(int x,int flow)
    {
        int ans = 0;
        if(x==t||flow==0)
            return flow;
        for(auto &i:f[x])//结构体无法在外部改变,外面只是创建了一个临时变量(相当结构体内部变量是私有属性)
        {
            if(i.w>0&&level[i.link]==level[x]+1)// 保证边权不为0 且按照深度dfs
            {
                int d = dfs(i.link, min(flow, i.w)); // 搜索,flow是最小的所以是min
                if(d==0)
                    level[i.link] = 0;
                if(d>0)
                {
                    i.w -= d;//正向边减少
                    f[i.link][i.position].w += d;// 反向边增加
                    flow -= d;
                    ans += d;
                    if(flow==0)
                        break;
                }
            }
        }
        return ans;
    }
    bool bfs()
    {
        q.push(s);
        memset(level, -1, sizeof(level));
        level[s] = 0;
        while(!q.empty())
        {
            int temp = q.front();
            q.pop();
            for(auto &i:f[temp])
            {
                if(i.w==0||level[i.link]!=-1)
                    continue;
                level[i.link] = level[temp] + 1;
                q.push(i.link);
            }
        }
        if(level[t]!=-1)
            return 1;
        return 0;
    }
    long long dinic()
    {
        long long ans = 0;
        while(bfs())
            ans += dfs(s, inf);
        
        return ans;
    }
    int main()
    {
        scanf("%d %d %d %d", &n,&m,&s,&t);
        for (int i = 1; i <= m;i++)
        {
            scanf("%d %d %d", &x, &y, &z);
            f[x].push_back((node){y, z,(int)f[y].size()});
            f[y].push_back((node){x, 0,(int)f[x].size()-1});// 获取x在y的第几条边
        }
        printf("%lld
    ", dinic());
        return 0;    
    } 
    

    费用流

    是不是应该和网络流放到一个分类里

    ek+spfa ((nm^2))

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1e4+5,inf=0x3f3f3f3f;
    int n, m, s, t, a,b,c,d;
    int pre[N],dis[N],flow[N],pos[N];
    bool use[N];
    long long mincost, maxflow;
    // pre记录回溯前驱,dis是 cost*w ,pre取代了level数组
    struct node
    {
        int link;
        int w;
        int cost;
        int position;
    };
    vector<node> f[N];
    queue<int> q;
    bool spfa()
    {
        while(!q.empty())
            q.pop();
        for (int i = 1; i <= n;i++)
        {
            dis[i] = inf;
            use[i] = 0;
            pre[i] = -1;
        }
        use[s] = 1;
        flow[s] = inf;
        dis[s] = 0;
        pre[s] = 0;
        q.push(s);
        while(!q.empty())
        {
            int temp = q.front();
            q.pop();
            use[temp] = 0;
            for (int i = 0; i < f[temp].size();i++)
            {
                node xx = f[temp][i];
                if(xx.w>0&&dis[xx.link]>dis[temp]+xx.cost)
                {
                    dis[xx.link] = dis[temp] + xx.cost;
                    pre[xx.link] = temp;
                    flow[xx.link] = min(flow[temp],xx.w);
                    pos[xx.link] = i;//记录这个点是temp的第几条边
                    if(use[xx.link]==0)
                    {
                        use[xx.link] = 1;
                        q.push(xx.link);
                    }
                }
            }
        }
        // for (int i = 1; i <= n;i++)
        //     printf("i=%d %d
    ", i,dis[i]);
        // printf("pret=%d
    ", pre[t]);
        if (pre[t] == -1)
            return 0;
        return 1;
    }
    void update()
    {
        int now = t;
        while(now!=s)
        {
            node &temp = f[pre[now]][pos[now]];
            temp.w -= flow[t];
            node &temp2=f[now][temp.position];
            temp2.w+= flow[t];
            now = pre[now];
        }
        mincost += flow[t] * dis[t];
        maxflow += flow[t];
    }
    long long mfmc()
    {
        while(spfa())
        {
            update();
        }
    }
    int main()
    {
        scanf("%d %d %d %d", &n,&m,&s,&t);
        for (int i = 1; i <= m;i++)
        {
            scanf("%d %d %d %d", &a, &b, &c,&d);
            f[a].push_back((node){b, c,d,(int)f[b].size()});
            f[b].push_back((node){a, 0,-d,(int)f[a].size()-1});// 注意翻遍花费是相反数
        }
        mfmc(); 
        printf("%lld %lld
    ",maxflow, mincost);
        return 0;    
    } 
    

    dinic+spfa 费用流 ((n^2m))

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1006,const_w=2e7+5;
    const long long inf = 1e17;
    int T,n, m, qx,zx,a,b,c,d,e,r[N];
    int pre[N];
    bool use[N];
    long long mcost,dis[N],flow[N],maxflow;
    // pre记录回溯前驱,dis是 cost*w ,pre取代了level数组
    struct node
    {
        int link;
        int w;
        int cost;
        int position;
    };
    vector<node> f[N];
    queue<int> q;
    void add_edge(int u,int v,int w,int cost)
    {
        //建立u->v的正向边
        f[u].push_back((node){v, w,cost,(int)f[v].size()});
        f[v].push_back((node){u, 0,-cost,(int)f[u].size()-1});
        // 注意花费是相反数
    }
    bool spfa()//最短路
    {
        while(!q.empty())
            q.pop();
        for (int i = 0; i <=2*n+1;i++)
        {
            dis[i] = inf;
            use[i] = 0;
            pre[i] = -1;
        }
        use[qx] = 1;
        flow[qx] = inf;
        dis[qx] = 0;
        pre[qx] = 0;
        q.push(qx);
        while(!q.empty())
        {
            int temp = q.front();
            q.pop();
            use[temp] = 0;
            for (int i = 0; i < f[temp].size();i++)
            {
                node xx = f[temp][i];
                if(xx.w>0&&dis[xx.link]>dis[temp]+xx.cost)
                {
                    dis[xx.link] = dis[temp] + xx.cost;
                    pre[xx.link] = temp;
                    flow[xx.link] = min(flow[temp],(long long)xx.w);
                    if(use[xx.link]==0)
                    {
                        use[xx.link] = 1;
                        q.push(xx.link);
                    }
                }
            }
        }
        if (pre[zx] == -1)
            return 0;
        return 1;
    }
    long long dfs(int x,long long flow)
    {
        long long ans = 0;
        if(x==2*n+1||flow==0)
            return flow;
        for(auto &i:f[x])//结构体无法在外部改变,外面只是创建了一个临时变量(相当结构体内部变量是私有属性)
        {
            if(i.w>0&&dis[i.link]==dis[x]+i.cost)// 保证边权不为0 且按照深度dfs
            {
                long long d = dfs(i.link, min(flow,(long long) i.w)); // 搜索,flow是最小的所以是min
                if(d>0)
                {
                    i.w -= d;//正向边减少
                    f[i.link][i.position].w += d;// 反向边增加
                    flow -= d;
                    ans += d;
                    mcost += d * i.cost;//多了个这个统计mcost
                    if(flow==0)
                        break;
                }
            }
        }
        return ans;
    }
    void mfmc()
    {
        qx = 0;
        zx = 2*n + 1;
        memset(flow, 0, sizeof(flow));
        mcost = 0;
        maxflow = 0;
        while(spfa())
        {
            maxflow+=dfs(0,inf);
        }
    }
    
    

    高精

    搞烦了实在不行换python

    似乎和图论没啥关系,加都加了算了

    string add(string str1,string str2)
    {
        string str;
        int len1=str1.length();
        int len2=str2.length();
        //前面补0,弄成长度相同
        if(len1<len2)
        {
            for(int i=1;i<=len2-len1;i++)
               str1="0"+str1;
        }
        else
        {
            for(int i=1;i<=len1-len2;i++)
               str2="0"+str2;
        }
        len1=str1.length();
        int cf=0;
        int temp;
        for(int i=len1-1;i>=0;i--)
        {
            temp=str1[i]-'0'+str2[i]-'0'+cf;
            cf=temp/10;
            temp%=10;
            str=char(temp+'0')+str;
        }
        if(cf!=0)  str=char(cf+'0')+str;
        return str;
    }
    
  • 相关阅读:
    每日一练4
    每日一练3
    每日一练2 字符串逆序输出
    每日一练1
    python全局变量
    python __file__ 与argv[0]
    python 静态方法和类方法
    常用的python库(不断更新)
    django 自定义用户user模型的三种方法
    实例详解Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化(三)
  • 原文地址:https://www.cnblogs.com/cherrypill/p/13154656.html
Copyright © 2011-2022 走看看