zoukankan      html  css  js  c++  java
  • POJ 图算法(3)

    图算法

    度限制最小生成树和第K最短路,分数规划

    poj1639, poj3621, poj2976

    poj2449poj3255poj2513

    最短路,最小生成树,二分图,最大流问题的相关理论

    poj3155,poj2112,poj1966,poj3281,poj1087,poj2289,poj3216,poj2446

    最优比率生成树

    poj27280/1分数规划应用)

    最小树形图

    poj3164(-刘算法)

    次小生成树

    poj1679(存在O(n^2)DP解法)

    2-SAT问题

    poj3207, poj3678, poj3683,poj3648, poj2723, poj2749

    无向图、有向图的最小环

    poj1734(floyd扩展)

    度限制最小生成树和第K最短路,分数规划  

     

    poj 1639

    标准的最小度限制生成树,详见:http://www.cnblogs.com/vongang/archive/2012/07/03/2575383.html

     

    poj  2976

    很裸的分数规划,给n个数对,a[i],b[i]可以从中删掉k个数对,然后使得sum(a)/sum(b)最大。

    很经典的分数规划问题。k = a(x)/b(x),转化成a(x) - k*b(x),对a(x) - k*b(x)进行排序,删掉前k小的数,然后求和。

    当求和为0时说明得到方程的解。

    View Code
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    #include <string>
    #include <set>
    #include <ctime>
    #include <queue>
    #include <map>
    
    #define CL(arr, val)    memset(arr, val, sizeof(arr))
    #define REP(i, n)       for((i) = 0; (i) < (n); ++(i))
    #define FOR(i, l, h)    for((i) = (l); (i) <= (h); ++(i))
    #define FORD(i, h, l)   for((i) = (h); (i) >= (l); --(i))
    #define L(x)    (x) << 1
    #define R(x)    (x) << 1 | 1
    #define MID(l, r)   (l + r) >> 1
    #define Min(x, y)   x < y ? x : y
    #define Max(x, y)   x < y ? y : x
    #define E(x)    (1 << (x))
    
    const double eps = 1e-8;
    typedef long long LL;
    using namespace std;
    
    const int N = (1<<10);
    
    double f[N], g[N];
    double G[N];
    int dbcmp(double x) {
        if(x > eps) return 1;
        else if(x < -eps)   return -1;
        return 0;
    }
    
    int main() {
        //freopen("data.in", "r", stdin);
    
        int n, k, i;
        while(~scanf("%d%d", &n, &k)) {
            if(n + k == 0)  break;
            REP(i, n)   scanf("%lf", f + i);
            REP(i, n)   scanf("%lf", g + i);
            double sum, l = 0, r = 1;
            while(dbcmp(r - l) > 0) {
                double m = (l + r)/2;
                REP(i, n)   G[i] = f[i] - g[i]*m;
                sort(G, G + n);
                for(sum = 0, i = k; i < n; ++i)  sum += G[i];
                if(dbcmp(sum) > 0)  l = m;
                else    r = m;
            }
            printf("%d\n", int(r*100 + 0.5));
        }
        return 0;
    }

     poj 3621

    题意:给一个无向图,找到一个环,使得环上的 点权之和/边权之和 最大。

    思路:这个还真不好想到。。。看的题解。sum(f[i])/sum(g[i][j]) == ans; 展开变形:

    g[1][2]* ans - f[1] + g[2][3]*ans + f[2] + ... = 0;

    这样就可以把g[i][j]*ans - f[i]当成一条边的另一个权值。二分ans的值,如果有一个环按这个权值计算出现负环,那么说明g[1][2]* ans - f[1] + g[2][3]*ans + f[2] + ... < 0 显然ans要增加,反之减少。

    注意g[i][j]*ans - f[i] 是double类型,在这里wa了好几次。。。。

    ans的上限定为1000就行。

    View Code
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    #include <string>
    #include <set>
    #include <ctime>
    #include <queue>
    #include <map>
    
    #define CL(arr, val)    memset(arr, val, sizeof(arr))
    #define REP(i, n)       for((i) = 0; (i) < (n); ++(i))
    #define FOR(i, l, h)    for((i) = (l); (i) <= (h); ++(i))
    #define FORD(i, h, l)   for((i) = (h); (i) >= (l); --(i))
    #define L(x)    (x) << 1
    #define R(x)    (x) << 1 | 1
    #define MID(l, r)   (l + r) >> 1
    #define Min(x, y)   x < y ? x : y
    #define Max(x, y)   x < y ? y : x
    #define E(x)    (1 << (x))
    
    const double eps = 1e-4;
    typedef long long LL;
    using namespace std;
    
    const int N = 1024;
    const double inf = ~0u>>1;
    
    struct node {
        int from;
        int to;
        int val;
        int next;
    } g[5100];
    
    int head[N], t;
    int cnt[N], f[N];
    double dis[N];
    bool inq[N];
    int q[1000000];
    
    int n, m;
    
    void add(int u, int v, int w) {
        g[t].from = u; g[t].to = v; g[t].val = w;
        g[t].next = head[u]; head[u] = t++;
    }
    
    int dbcmp(double x) {
        if(x > eps) return 1;
        else if(x < -eps)   return -1;
        return 0;
    }
    
    bool spfa(double ans) {
        int u, v, i;
        double w;
        int l = 0, r = 0;
        for(i = 1; i <= n; ++i) {
            dis[i] = inf; cnt[i] = 0; inq[i] = false;
        }
        q[r++] = 1; dis[1] = 0;
        inq[1] = true; cnt[1]++;
    
    
        while(l < r) {
            u = q[l++];
            for(i = head[u]; i != -1; i = g[i].next) {
                v = g[i].to; w = g[i].val*ans - f[g[i].from];
                if(dis[v] > dis[u] + w) {
                    dis[v] = dis[u] + w;
                    if(!inq[v]) {
                        cnt[v] ++ ;
                        if(cnt[v] > n)  return false;
                        inq[v] = true;
                        q[r++] = v;
                    }
                }
            }
            inq[u] = false;
        }
        return true;
    }
    
    
    int main() {
        //freopen("data.in", "r", stdin);
    
        int i, x, y, z;
        while(~scanf("%d%d", &n, &m)) {
            CL(head, -1); t = 0;
            CL(f, 0);
            FOR(i, 1, n)    scanf("%d", f + i);
            FOR(i, 1, m)  {
                scanf("%d%d%d", &x, &y, &z);
                add(x, y, z);
            }
            double l = 0, r = 100, mid;
            while(dbcmp(r - l) > 0) {
                mid = (l + r)/2;
                if(spfa(mid))   r = mid;
                else    l = mid;
            }
            printf("%.2f\n", r);
        }
        return 0;
    }

    poj 2449

    裸第k短路:表示没有接触过A*,看论文看的眼冒金星。启发函数好神奇。。。。

    详见:http://www.cnblogs.com/vongang/archive/2012/07/17/2594737.html

    可以作为这类问题的模板

    View Code
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    #include <string>
    #include <set>
    #include <ctime>
    #include <queue>
    #include <map>
    #include <sstream>
    
    #define CL(arr, val)    memset(arr, val, sizeof(arr))
    #define REP(i, n)       for((i) = 0; (i) < (n); ++(i))
    #define FOR(i, l, h)    for((i) = (l); (i) <= (h); ++(i))
    #define FORD(i, h, l)   for((i) = (h); (i) >= (l); --(i))
    #define L(x)    (x) << 1
    #define R(x)    (x) << 1 | 1
    #define MID(l, r)   (l + r) >> 1
    #define Min(x, y)   x < y ? x : y
    #define Max(x, y)   x < y ? y : x
    #define E(x)    (1 << (x))
    
    const double eps = 1e-4;
    typedef long long LL;
    using namespace std;
    
    const int N = 1024;
    const int M = 100010;
    const int inf = ~0u>>2;
    
    struct edg {
        int to;
        int val;
        int next;
        edg() {}
        edg(int a, int b, int c): to(a), val(b), next(c) {}
    } g[M<<1], rg[M<<1];
    
    struct node {
        int f, g, v;
        node() {}
        node(int a, int b, int c) : f(a), g(b), v(c) {}
    
        bool operator < (const node& x) const {
            return x.f < f;
        }
    };
    
    int inq[N];
    int head[N];
    int rhead[N];
    int dis[N];
    int t, k;
    
    void init() {
        CL(head, -1);
        CL(rhead, -1);
        CL(inq, 0);
        t = 0;
        for(int i = 0; i < N; ++i)  dis[i] = inf;
    }
    
    void add(int u, int v, int w) {
        g[t] = edg(v, w, head[u]);
        rg[t] = edg(u, w, rhead[v]);
        head[u] = t;
        rhead[v] = t++;
    }
    
    void spfa(int ed) {
        int i, u, v, w;
        queue<int> q;
        q.push(ed);
        inq[ed] = 1;
        dis[ed] = 0;
    
        while(!q.empty()) {
            u = q.front();
    
            for(i = rhead[u]; i != -1; i = rg[i].next) {
                v = rg[i].to; w = rg[i].val;
                if(dis[v] > dis[u] + w) {
                    dis[v] = dis[u] + w;
                    if(!inq[v]) { inq[v] = 1; q.push(v);}
                }
            }
            inq[u] = 0; q.pop();
        }
    }
    
    int A_star(int st, int ed) {
        priority_queue<node> Q;
        if(dis[st] == inf)  return -1;
        int v, w;
        CL(inq, 0);
        Q.push(node(dis[st], 0, st));
    
        while(!Q.empty()) {
            node cur = Q.top();
            Q.pop(); inq[cur.v] ++;
            if(inq[ed] == k)    return cur.f;
            if(inq[cur.v] > k)  continue;
    
            for(int i = head[cur.v]; i != -1; i = g[i].next) {
                v = g[i].to; w = g[i].val;
                node New(dis[v] + cur.g + w, cur.g + w, v);
                Q.push(New);
            }
        }
    
        return -1;
    }
    
    int main() {
        //freopen("data.in", "r", stdin);
    
        int n, m, i;
        int u, v, w;
        int st, ed;
        init();
        scanf("%d%d", &n, &m);
        for(i = 0; i < m; ++i) {
            scanf("%d%d%d", &u, &v, &w);
            add(u, v, w);
        }
        scanf("%d%d%d", &st, &ed, &k);
    
        spfa(ed);
        if(st == ed)    k++;
        printf("%d\n", A_star(st, ed));
        return 0;
    }

    POJ 3255

    题意是求1到n的次短路

    改改模板就可以了,不过这里是无向图,要加双向边的。。。

    View Code
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    #include <string>
    #include <set>
    #include <ctime>
    #include <queue>
    #include <map>
    #include <sstream>
    
    #define CL(arr, val)    memset(arr, val, sizeof(arr))
    #define REP(i, n)       for((i) = 0; (i) < (n); ++(i))
    #define FOR(i, l, h)    for((i) = (l); (i) <= (h); ++(i))
    #define FORD(i, h, l)   for((i) = (h); (i) >= (l); --(i))
    #define L(x)    (x) << 1
    #define R(x)    (x) << 1 | 1
    #define MID(l, r)   (l + r) >> 1
    #define Min(x, y)   x < y ? x : y
    #define Max(x, y)   x < y ? y : x
    #define E(x)    (1 << (x))
    
    const double eps = 1e-4;
    typedef long long LL;
    using namespace std;
    
    const int N = 5024;
    const int M = 100010;
    const int inf = ~0u>>2;
    
    struct edg {
        int to;
        int val;
        int next;
        edg() {}
        edg(int a, int b, int c): to(a), val(b), next(c) {}
    } g[M<<1], rg[M<<1];
    
    struct node {
        int f, g, v;
        node() {}
        node(int a, int b, int c) : f(a), g(b), v(c) {}
    
        bool operator < (const node& x) const {
            return x.f < f;
        }
    };
    
    int inq[N];
    int head[N];
    int rhead[N];
    int dis[N];
    int t, k;
    
    void init() {
        CL(head, -1);
        CL(rhead, -1);
        CL(inq, 0);
        t = 0;
        for(int i = 0; i < N; ++i)  dis[i] = inf;
    }
    
    void add(int u, int v, int w) {
        g[t] = edg(v, w, head[u]);
        rg[t] = edg(u, w, rhead[v]);
        head[u] = t;
        rhead[v] = t++;
    
        g[t] = edg(u, w, head[v]);
        rg[t] = edg(v, w, rhead[u]);
        head[v] = t;
        rhead[u] = t++;
    }
    
    void spfa(int ed) {
        int i, u, v, w;
        queue<int> q;
        q.push(ed);
        inq[ed] = 1;
        dis[ed] = 0;
    
        while(!q.empty()) {
            u = q.front();
    
            for(i = rhead[u]; i != -1; i = rg[i].next) {
                v = rg[i].to; w = rg[i].val;
                if(dis[v] > dis[u] + w) {
                    dis[v] = dis[u] + w;
                    if(!inq[v]) { inq[v] = 1; q.push(v);}
                }
            }
            inq[u] = 0; q.pop();
        }
    }
    
    int A_star(int st, int ed) {
        priority_queue<node> Q;
        if(dis[st] == inf)  return -1;
        int v, w;
        CL(inq, 0);
        Q.push(node(dis[st], 0, st));
    
        while(!Q.empty()) {
            node cur = Q.top();
            Q.pop(); inq[cur.v] ++;
            if(inq[ed] == k)    return cur.f;
            if(inq[cur.v] > k)  continue;
    
            for(int i = head[cur.v]; i != -1; i = g[i].next) {
                v = g[i].to; w = g[i].val;
                node New(dis[v] + cur.g + w, cur.g + w, v);
                Q.push(New);
            }
        }
    
        return -1;
    }
    
    int main() {
        //freopen("data.in", "r", stdin);
    
        int n, m, i;
        int u, v, w;
        int st, ed;
        init();
        scanf("%d%d", &n, &m);
        for(i = 0; i < m; ++i) {
            scanf("%d%d%d", &u, &v, &w);
            add(u, v, w);
        }
        st = 1; ed = n; k = 2;
    
        spfa(ed);
        if(st == ed)    k++;
        printf("%d\n", A_star(st, ed));
        return 0;
    }

    最优比率生成树

    POJ 2728

    一个典故:2005年杭州赛区。。。楼教高速AC此题,打乱了赛场节奏,顺利夺冠。。。

    最优比例生成树模板题,详见:http://www.cnblogs.com/vongang/archive/2012/07/17/2596441.html

    最小树形图 

    POJ 3164 && HDU 2121

    http://www.cnblogs.com/vongang/archive/2012/07/18/2596851.html

    次小生成树 

    POJ 1679

    http://www.cnblogs.com/vongang/archive/2012/07/18/2597739.html

    2-SAT问题 

    POJ 2-SAT六题 :http://www.cnblogs.com/vongang/archive/2012/02/16/2353770.html 

    无向图、有向图的最小环 

    POJ 1734

    http://www.cnblogs.com/vongang/archive/2012/07/18/2598167.html

  • 相关阅读:
    高计数率下的梯形成形算法的计数率矫正
    梯形成形算法
    就业还是和一起创业?
    努力,还是会前进,世界一定是越来越好。
    一日黑客,SQL注入
    钱,money,人生
    一些技术生词记录
    江苏省计算机C语言考试记录
    NVIDIA显卡设置
    大二寒假 之 丢失的13天
  • 原文地址:https://www.cnblogs.com/vongang/p/2573611.html
Copyright © 2011-2022 走看看