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

  • 相关阅读:
    python json 和 pickle的补充 hashlib configparser logging
    go 流程语句 if goto for swich
    go array slice map make new操作
    go 基础
    块级元素 行内元素 空元素
    咽炎就医用药(慢性肥厚性咽炎)
    春季感冒是风寒还是风热(转的文章)
    秋季感冒 咳嗽 怎么选药
    解决IE浏览器“无法显示此网页”的问题
    常用的 css 样式 记录
  • 原文地址:https://www.cnblogs.com/vongang/p/2573611.html
Copyright © 2011-2022 走看看