hdu4966 hdu4009 (最小树形图)

来源:互联网 发布:linux 查看目录大小 编辑:程序博客网 时间:2024/05/19 10:41


hdu4966

一开始以为是网络流,各种坑队友,后来才发现是相当裸的最小树形图。


添加一个根,连边到各课程的0级,权值为0。

然后每个课程从(i)级连边到(i-1)级,权值为0.

最后根据课程间的关系再连边。


#include <cstdio>#include <cstring>#include <iostream>using namespace std;const int maxn = 555, maxm = 500 * 2000, inf = 1e9;struct Edge{    int u, v, w;    Edge(){}    Edge(int u, int v, int w):    u(u), v(v), w(w){}}e[maxm];int ec;int lev[55], begid[55], endid[55];int N;int mincost[maxn], pre[maxn];bool makeMin(int root){    for(int i = 1; i <= N; i++) mincost[i] = inf;    for(int i = 0; i < ec; i++){        if(e[i].u == e[i].v) continue;        int v = e[i].v;        if(mincost[v] > e[i].w){            mincost[v] = e[i].w;            pre[v] = e[i].u;        }        }    for(int i = 1; i <= N; i++){        if(i == root) continue;        if(mincost[i] == inf) return false;    }    return true;}int vis[maxn];int id[maxn];bool existCircle(int root, int &res){    memset(vis, -1, sizeof(vis));    memset(id, -1, sizeof(id));    int ind = 1;    mincost[root] = 0;    for(int i = 1; i <= N; i++){        int v = i;        res += mincost[i];        while(vis[v] != i && v != root && id[v] == -1) {            vis[v] = i, v = pre[v];        }        if(v != root && id[v] == -1){            for(int u = pre[v]; u != v; u = pre[u]) id[u] = ind;            id[v] = ind++;        }    }    if(ind == 1) return false;    for(int i = 1; i <= N; i++)        if(id[i] == -1) id[i] = ind++;    N = ind - 1;    return true;}void update(){    for(int i = 0; i < ec; i++){        int v = e[i].v;        e[i].u = id[e[i].u];        e[i].v = id[e[i].v];        if(e[i].u == e[i].v) continue;        e[i].w -= mincost[v];                }}int DMST(int root){    int res = 0;    while(1){        if(!makeMin(root)) return -1;        if(!existCircle(root, res)) return res;        update();        root = id[root];    }    return -1;}int main(){//    freopen("in", "r", stdin);//    freopen("out", "w", stdout);    int n, m;    while(scanf("%d%d", &n, &m), n&&m){        for(int i = 1; i <= n; i++) scanf("%d", lev+i);            lev[0] = 1, begid[0] = 0;            for(int i = 1; i <= n; i++) begid[i] = begid[i-1] + lev[i-1] + 1;        N = begid[n] + lev[n];                int c, l, d, r, w;        int root = 1;        ec = 0;        for(int i = 1; i <= n; i++)        e[ec++] = Edge(root, begid[i], 0);        for(int i = 1; i <= n; i++){            for(int j = 1; j <= lev[i]; j++){                int u = begid[i] + j, v = u - 1;                e[ec++] = Edge(u, v, 0);            }        }        for(int i = 0; i < m; i++){            scanf("%d%d%d%d%d", &c, &l, &d, &r, &w);            int v = begid[d] + r;            for(int j = l, u = begid[c] + l; j <= lev[c]; u++, j++){                e[ec++] = Edge(u, v, w);                }        }            int ans = DMST(root);        if(~ans) printf("%d\n", ans);        else puts("-1");    }    return 0;}


hdu4009

一个村子有n个房子,每间房子的坐标为(x,y,z)

如果自己打井,则代价为 z * A

如果从别的房子那里连水管过来,则代价为 两点的曼哈顿距离*B; 如果源点的z比此地的z小,则代价要加上C

求让所有房子都有水的最小代价。(怎么样都能保证每个房子都有水,所以根本不会输出“poor XiaoA”...)


加入根,然后根到每个点的权值为该点自己打井的代价,

然后其他的根据输入建边。

一个优化是,如果某个点从其他点连的边代价比直接自己打井还大,那么就可以不连。

然后就是IO输入优化了。

#include <cstdio>#include <cstring>#include <iostream>using namespace std;const int maxn = 1002, maxm = 1002 * 1004, inf = 0x3f3f3f3f;#define ABS(x) ( (x)>0? (x) : (-(x)) )struct Edge{    int u, v, w;    Edge(){}    Edge(int u, int v, int w):    u(u), v(v), w(w){}}e[maxm];int ec;int N;int mincost[maxn], pre[maxn];bool makeMin(int root){    memset(mincost, 0x3f, sizeof(mincost));    for(int i = 0; i < ec; i++){        if(e[i].u == e[i].v) continue;        int v = e[i].v;        if(mincost[v] > e[i].w){            mincost[v] = e[i].w;            pre[v] = e[i].u;        }        }    for(int i = 1; i <= N; i++){        if(i == root) continue;        if(mincost[i] == inf) return false;    }    return true;}int vis[maxn];int id[maxn];bool existCircle(int root, int &res){    memset(vis, -1, sizeof(vis));    memset(id, -1, sizeof(id));    int ind = 1;    mincost[root] = 0;    for(int i = 1; i <= N; i++){        int v = i;        res += mincost[i];        while(vis[v] != i && v != root && id[v] == -1) {            vis[v] = i, v = pre[v];        }        if(v != root && id[v] == -1){            for(int u = pre[v]; u != v; u = pre[u]) id[u] = ind;            id[v] = ind++;        }    }    if(ind == 1) return false;    for(int i = 1; i <= N; i++)        if(id[i] == -1) id[i] = ind++;    N = ind - 1;    return true;}void update(){    for(int i = 0; i < ec; i++){        int v = e[i].v;        e[i].u = id[e[i].u];        e[i].v = id[e[i].v];        if(e[i].u == e[i].v) continue;        e[i].w -= mincost[v];                }}int DMST(int root){    int res = 0;    while(1){        if(!makeMin(root)) return -1;        if(!existCircle(root, res)) return res;        update();        root = id[root];    }    return -1;}struct Pos{    int x, y, z;}p[maxn];inline int dis(const Pos& a, const Pos& b){    return ABS(a.x-b.x) + ABS(a.y-b.y) + ABS(a.z-b.z);    }inline int nextInt(){    char ch = ' ';    int res = 0;    while(!isdigit(ch)) ch = getchar();    while(isdigit(ch)){        res *= 10;        res += ch - '0';        ch = getchar();    }    return res;}int self[maxn];int main(){//    freopen("in.txt", "r", stdin);//    freopen("out", "w", stdout);    int n, x, y, z;    while(n = nextInt(), x = nextInt(), y = nextInt(), z = nextInt(), n && x && y && z){        ec = 0;        N = n + 1;        for(int i = 1; i <= n; i++) {         p[i].x = nextInt();         p[i].y = nextInt();         p[i].z = nextInt();    }        for(int i = 1; i <= n; i++){            self[i] = p[i].z * x;            e[ec++] = Edge(N, i, self[i]);       }        for(int i = 1; i <= n; i++){            int k;        k = nextInt();            for(int j = 0, v, w; j < k; j++){                v = nextInt();                if(v == i) continue;                w = dis(p[i], p[v]);                w *= y;        if(p[i].z < p[v].z)                    w += z;            if(w >= self[v]) continue;                    e[ec++] = Edge(i, v, w);            }        }        printf("%d\n", DMST(N));    }    return 0;}



0 0