2017年ACM模板(常用)弱渣整理 三、图论

一、拓扑排序

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 1000;
struct Node{
    int indegree;//入度数 
    int num;     //排序number
    int id;      //编号
}N[maxn];
int V,E;
int d[maxn][maxn];//邻接矩阵

/*初始化*/
void Init()
{
    for(int i=0; i<V; i++)
    {
        N[i].indegree = 0;
        N[i].num = NULL;
        N[i].id = i;
    }
    memset(d,0,sizeof(d));
    return;
}
int main()
{
    scanf("%d%d",&V,&E);
    Init();

    int s,t;
    for(int i=0; i<E; i++)
    {
        scanf("%d%d",&s,&t);
        d[s][t] = 1;
        N[t].indegree++;//子结点的入度加一
    }

    int counter = 0;
    queue<Node> q;
    for(int i=0; i<V; i++)
    {
        if(!N[i].indegree)
        {
            q.push(N[i]);
        }
    }

    while(!q.empty())
    {
        Node v = q.front(); q.pop();
        N[v.id].num = counter++;

        for(int i=0; i<V; i++)
        {
            if(d[v.id][i])
            {
                if((--(N[i].indegree))==0)
                {
                    q.push(N[i]);
                }
            }
        }
    }
    for(int i=0; i<V; i++)
    {
        printf("%d ",N[i].num);
    }
    return 0;
}

二、BFS

void bfs(int s)
{
    queue<int>q;    //用队列实现
    q.push(s);      //插入开始顶点
    for(int i=0;i<n;i++)
    {
        d[i] = INF; //初始化为INF
    }
    d[s] = 0;       
    while(!q.empty())
    {
        int v = q.front(); q.pop();
        for(int i=1;i<=n;i++)
        {
            if(metrix[v][i]&&d[i]==INF)
            {
                d[i] = d[v] + 1;
                q.push(i);
            }
        }
    }
}

三、最短路径问题

1.Bellman-Ford算法

#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 1000;
const int INF = 10000000;
int n,e;
int d[maxn],pre[maxn];
struct edge{
    int from,to,cost;
};
edge es[maxn];
void init(int s)
{
    for(int i=0; i<n; i++)
    {
        d[i] = INF;
        pre[i] = NULL;
    }
    d[s] = 0;
    return;
}

void Bellman_Ford(int s)
{
    init(s);
    while(true)
    {
        bool updata = false;
        for(int i=0; i<e; i++)
        {
            edge e = es[i];
            if(d[e.from]!=INF && d[e.to] > d[e.from] +e.cost)
            {
                d[e.to] = d[e.from] + e.cost;//更新最短路径 
                pre[e.to] = e.from;          //更新父结点 
                updata = true;
            }
        }
        if(!updata) break;
    }
}

int main()
{
    scanf("%d%d",&n,&e);
    int s,t,c;
    for(int i=0; i<e; i++)
    {
        scanf("%d%d%d",&s,&t,&c);
        es[i].from = s;
        es[i].to = t;
        es[i].cost = c;
    }
    Bellman_Ford(0);
    for(int i=0; i<n; i++)
    {
        printf("%d ",d[i]);
    }
    printf("\n");
    for(int i=0; i<n; i++)
    {
        printf("%d ",pre[i]);
    }
    return 0;
}
判断负圈:
bool find_negative_loop()
{
    memset(d,0,sizeof(d));

    for(int i=0; i<n; i++)
    {
        for(int j=0; j<e; j++)
        {
            egde e = es[j];
            if(d[e.to] > d[e.from] + e.cost)
            {
                d[e.to] = d[e.from] + e.cost;
                if(i == V - 1) return true;//如果第n次仍然更新了,则存在负圈
             } 
        }   
    }
    return false;   
}

2.Dijksta算法

#include<cstdio>
#include<queue>
#include<vector>
using namespace std;
const int maxn = 1000;
const int INF = 99999999;
struct edge{
    int to,cost;
    edge(int to, int cost) : to(to), cost(cost){}
};  
typedef pair<int,int> P;//first是最短路径,second是顶点的编号 
int d[maxn];
int V,E;
vector<edge> G[maxn];

void dijkstra(int s)
{
    priority_queue<P,vector<P>,greater<P> > q;
    fill(d, d + V, INF);
    d[s] = 0;
    q.push(P(0,s));

    while(!q.empty())
    {
        P p = q.top(); q.pop();
        int v = p.second;
        if(d[v] < p.first) continue;
        for(int i=0; i<G[v].size(); i++)
        {
            edge e = G[v][i];
            if(d[e.to] > d[v] + e.cost)
            {
                d[e.to] = d[v] + e.cost;
                q.push(P(d[e.to],e.to)); 
            }
        }
    }
 } 
int main()
{
    scanf("%d%d",&V,&E);
    int s,t,c;
    for(int i=0;i<E;i++)
    {
        scanf("%d%d%d",&s,&t,&c);
        G[s].push_back(edge(t,c));
    }
    dijkstra(0);
    for(int i=0; i<V; i++)
    {
        printf("%d ",d[i]);
    }
    return 0;
} 

3. 任意结点对最短路

Floyd-Warshall算法
/*初始化*/
void Init()
{
    for(int i=0; i<V; i++)
    {
        for(int j=0; j<V; j++)
        {
            if(i==j) d[i][j] = 0;
            else if(!cost[i][j])
            {
                d[i][j] = INF;
            }
            else
            d[i][j] = cost[i][j];
        }
    }
    return;
}

    void warshall_floyd()
{
    for(int k=0; k<V; k++)
    {
        for(int i=0; i<V; i++)
        {
            for(int j=0; j<V; j++)
            {
                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
            }
        }
    }
    return;
}

4.无权最短路径

使用BFS即可。


四、最小生成树

Kruskal算法:(并查集)

int kruskal()
{
    sort(es, es+E, cmp);
    init_union_find(V);
    int res = 0;
    for(int i=0; i<E; i++)
    {
        edge e = es[i];
        if(!same(e.u, e.v))
        {
            unite(e.u, e.v);
            res += e.cost;
        }
    }
    return res;
} 

五、欧拉图

先判断一个图是否为连通图,如果不是,那么直接输出“No”;如果是,那么就需要再判断每一个顶点的度数,如果奇点的数目为0或2则输出”Yes”,否则输出”No”。
连通图的判断使用并查集


六、最大流问题

Ford-Fulkerson算法

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 1000+10;
const int INF = 1000000000;
struct edge{
    int to, cap, rev;
}; 

vector<edge> G[maxn];
bool used[maxn];
int V,E;

/*向图中增加一条从s到t为cap的边*/
void add_edge(int from, int to, int cap)
{
    G[from].push_back((edge){to, cap, G[to].size()});
    G[to].push_back((edge){from, 0, G[from].size() - 1});
} 

/*通过DFS找增广路*/
int dfs(int v, int t, int f)
{
    if(v == t) return f;
    used[v] = true;
    for(int i=0; i<G[v].size(); i++)
    {
        edge &e = G[v][i];
        if(!used[e.to] && e.cap > 0)
        {
            int d = dfs(e.to, t, min(f, e.cap));
            if(d > 0)
            {
                e.cap -= d;
                G[e.to][e.rev].cap += d;
                return d;
            }
        }
    }
    return 0;
}

/*求解从s到t的最大流*/
int max_flow(int s, int t)
{
    int flow = 0;
    for(; ;)
    {
        memset(used, 0, sizeof(used));
        int f = dfs(s, t, INF);
        if(f == 0) return flow;
        flow += f;
    }
}

int main()
{
    scanf("%d%d",&V,&E);
    int s,t,e;
    for(int i=0; i<E; i++)
    {
        scanf("%d%d%d",&s,&t,&e);
        add_edge(s, t, e);  
    }
    printf("%d\n", max_flow(0, V-1));
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 图论 3 1.1 术语 3 1.2 独立集、覆盖集、支配集之间关系 3 1.3 DFS 4 1.3.1 割顶 6 1.3.2 桥 7 1.3.3 强连通分量 7 1.4 最小点基 7 1.5 拓扑排序 7 1.6 欧拉路 8 1.7 哈密顿路(正确?) 9 1.8 Bellman-ford 9 1.9 差分约束系统(用bellman-ford解) 10 1.10 dag最短路径 10 1.11 二分图匹配 11 1.11.1 匈牙利算法 11 1.11.2 KM算法 12 1.12 网络流 15 1.12.1 最大流 15 1.12.2 上下界的网络的最大流 17 1.12.3 上下界的网络的最小流 17 1.12.4 最小费用最大流 18 1.12.5 上下界的网络的最小费用最小流 21 2 数论 21 2.1 最大公约数gcd 21 2.2 最小公倍数lcm 22 2.3 快速幂取模B^LmodP(O(logb)) 22 2.4 Fermat小定理 22 2.5 Rabin-Miller伪素数测试 22 2.6 Pollard-rho 22 2.7 扩展欧几里德算法extended-gcd 24 2.8 欧拉定理 24 2.9 线性同余方程ax≡b(mod n) 24 2.10 中国剩余定理 25 2.11 Discrete Logging(BL == N (mod P)) 26 2.12 N!最后一个不为0的数字 27 2.13 2^14以内的素数 27 3 数据结构 31 3.1 堆(最小堆) 31 3.1.1 删除最小值元素: 31 3.1.2 插入元素和向上调整: 32 3.1.3 堆的建立 32 3.2 并查集 32 3.3 树状数组 33 3.3.1 LOWBIT 33 3.3.2 修改a[p] 33 3.3.3 前缀和A[1]+…+A[p] 34 3.3.4 一个二维树状数组的程序 34 3.4 线段树 35 3.5 字符串 38 3.5.1 字符串哈希 38 3.5.2 KMP算法 40 4 计算几何 41 4.1 直线交点 41 4.2 判断线段相交 41 4.3 点外接圆圆心 42 4.4 判断点在多边形内 43 4.5 两圆交面积 43 4.6 最小包围圆 44 4.7 经纬度坐标 46 4.8 凸包 46 5 Problem 48 5.1 RMQ-LCA 48 5.1.1 Range Minimum Query(RMQ) 49 5.1.2 Lowest Common Ancestor (LCA) 53 5.1.3 Reduction from LCA to RMQ 56 5.1.4 From RMQ to LCA 57 5.1.5 An<O(N), O(1)> algorithm for the restricted RMQ 60 5.1.6 An AC programme 61 5.2 最长公共子序列LCS 64 5.3 最长上升子序列/最长不下降子序列(LIS) 65 5.3.1 O(n^2) 65 5.3.2 O(nlogn) 66 5.4 Joseph问题 67 5.5 0/1背包问题 68 6 组合数学相关 69 6.1 The Number of the Same BST 69 6.2 排列生成 71 6.3 逆序 72 6.3.1 归并排序求逆序 72 7 数值分析 72 7.1 二分法 72 7.2 迭代法(x=f(x)) 73 7.3 牛顿迭代 74 7.4 数值积分 74 7.5 高斯消元 75 8 其它 77
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值