mathematical method

mathematical method

曲线拟合

  • 指数 \(lnY = lna + bX\)
  • 对数 \(Y = blnX + a\)
  • 幂函数 \(lgY=lga+blgX\)

多元线性回归模型

  • 回归分析中有两个或者两个以上的自变量,就是多元回归
  • 最小化残差平方和 SSE

图论: Floyd

#include <iostream>

using namespace std;

const int maxn = 200;

int n,s,t;
int a[maxn+1][maxn+1];

void init()
{
    int m,u,v;
    cin >> n >> m;
    for(int i =1; i<=n; i++)
        for(int j =1; j<=n; j++)
            a[i][j] = -1;
    for(int i = 1; i<=m; i++)
        cin >> u >> v >> a[u][v];
    cin >> s >> t;
}


void floyd()
{
    int i,j,k;
    for(k=1; k<=n; k++)
        for(i=1; i<=n; i++)
            for(j=1; j<=n; j++)
            {
                if(a[i][k]!=-1&&a[k][j]!=-1)
                    a[i][j] = min(a[i][j],a[i][k]+a[k][j]);
            }
}

int main()
{
    init();
    floyd();
    cout << a[s][t]+a[t][s]<<endl;
    return 0;
}

图论: Prim 算法

  • 解决最小生成树问题
  • 采用的方法是加点法
  • 在所有加过的点中找到距离其他点最短路径的点&&不能构成回路,加入集合,
//这里使用无向图
#include <iostream>

using namespace std;

const int MAXN = 2001;
const int INF = 99999999;

int n,e;
int w[MAXN][MAXN];
int mincount[MAXN]; //从初始顶点到该顶点的最小权值


void init()
{
    int i,j;
    int tx,ty;
    for(i = 0; i<=MAXN; i++)
        for(j =0; j<MAXN; j++)
            w[i][j] = INF;

    cin >> n >> e;

    for(i = 1; i<=e; i++)
    {
        cin >> tx >> ty >> w[tx][ty];
        w[ty][tx] = w[tx][ty];
    }
}

void prim(int s)   //从标号为s处开始生成树
{
    int i,j,cnt = 0,min; // cnt 是生成树所有边的权值之和
    int k;
    for(i = 1; i<= n; i++)
        mincount[i] = w[s][i]; //  初始化,设w[1][i]是初始点k到i的最小权值,如果没有就设为INF
    mincount[s] = 0;

    for(i = 1; i < n; i++) //一共有n-1次
    {
        min = INF;
        for(j = 1; j <= n; j++)
        {
            if(mincount[j]!=0 && mincount[j]<min)
            {
                min = mincount[j];
                k = j;        //记录该点
            }
            mincount[k] = 0;//将该点加入到最小生成树中
            cnt += min;   //将这条边权值加入到最小生成树中

            for(j = 1;j<=n;j++)  //修正初始点到每个点的最小权值
            {
                  if(w[k][j]<mincount[j])
                        mincount[j] = w[k][j];
            }
        }
    }
    cout << cnt << endl;
}

int main()
{
    init();
    prim(1);
    return 0;
}

图论: Kruskal算法 - 加边法

  • 主要用到的是并查集
#include <iostream>

using namespace std;

const int MAXN = 2000;
const int INF = 99999999;
int n,e;// n是点的数量,e是边的数量
int x[MAXN],y[MAXN],w[MAXN];
int parent[MAXN];

int Find(int x)
{
    if(parent[x] == x)
        return x;
    else
        return parent[x] = Find(parent[x]);
}


void Merge(int a,int b)
{
    int pa = Find(a);
    int pb = Find(b);
    if(pb < pa)
        swap(pb,pa);
    if(pa!=pb)
        parent[pa] = pb;
}


void kruskal()
{
    int i,p,ans;  //p是已经加入的边数,ans是加入边的边权之和

    for(i = 1; i<=n ; i++) //initialize
    {
        parent[i] = i;
    }

    p = 1;
    ans = 0;

    for(i = 1; i <= e; i++)
    {
        if(Find(x[i])!=Find(y[i]))// 两点没有在同一个集合中,归并两个集合
        {
            ans += w[i];
            Merge(x[i],y[i]);
            p++;
            if(p == n)    //这里不是n-1,因为初始化的时候,p = 1
            {
                cout << ans << endl;
                return;
            }
        }
    }
    return;
}


void sort(int i, int j)
{
    if(i >=j)
        return;
    int m,n,k;
    m = i;
    n = j;
    k = w[(i+j)>>1];
    while(m <= n)
    {
        while(w[m]<k)
            m++;
        while(w[n]>k)
            n--;
        if(m <= n)
        {
            swap(x[m],x[n]);
            swap(y[m],y[n]);
            swap(w[m],w[n]);
            m++;
            n--;
        }
    }
    sort(i,n);
    sort(m,j);
}


int main()
{
    int i,j;
    cin >> n >> e;
    for(i = 1; i <= e ; i++)
    {
        cin >> x[i] >> y[i] >> w[i];
    }
    sort(1,e);
    kruskal();
    return 0;
}

最大流 - Ford fulkerson算法

残余网络 & 增广路径

Ford-Fulkerson方法的正确性依赖于这个定理:当残存网络中不存在一条从s到t的增广路径,那么该图已经达到最大流。

伪代码

Ford-Fulkerson
    for <u,v> ∈ E
        <u,v>.f = 0
    while find a route from s to t in e
            m = min(<u,v>.f, <u,v>  ∈ route)
        for <u,v> ∈ route
            if <u,v>  ∈ f
                <u,v>.f = <u,v>.f + m
            else
                <v,u>.f = <v,u>.f - m

实现过程中的重点自傲与如何寻找增广路径

  • 可以使用广度搜索
  • 可以用Bellmanford算法进行计算
  • 残存网络就是在流网络的基础上改变的,容量仍然保持不变,只改变已经用过的容量.将其反向如果流量为0那就不用再表示在图上了
#include<stdio.h>
#include<stdlib.h>
#include<vector>
#include<algorithm>

#define MAXVEX 100
#define INF 65535

//用于表示边的结构体
struct edge
{
    int to;//终点
    int cap;//容量
    int rev;//反向边
};
std::vector<edge>G[MAXVEX];//图的邻接表表示
bool used[MAXVEX];//DFS中用到的访问标记

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

//通过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, std::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;
    }
}
posted @ 2018-02-04 00:00  pprp  阅读(273)  评论(0编辑  收藏  举报