HDU4085 斯坦纳树

来源:互联网 发布:杭州紫府网络 编辑:程序博客网 时间:2024/04/27 15:22

http://acm.hdu.edu.cn/showproblem.php?pid=4085


   新学习了斯坦纳树,记录一下。

   我是从http://endlesscount.blog.163.com/blog/static/821197872012525113427573/学习的斯坦纳树


   斯坦纳树用于解决保证指定节点连接的情况下,求边权总和最小的问题。算是用最短路辅助的DP问题

   

    斯坦纳树核心部分:

 for(int state = 0; state < endState; state++){    for(int root = 1; root <= n; root++){        for (int sub = (state-1)&state; sub; sub = (sub-1)&state){            mincost[root][state] = min(mincost[root][state],                                        mincost[root][sub|st[root]] + mincost[root][(state-sub)|st[root]]);        }        if(mincost[root][state] < INF){            isVis[root][state] = true;            que.push(root*base+state);        }    }    spfa(); }

mincost[root][state] 表示以root为根,连接状态为state构造出来的图的边权总和, sub 是 state 的子状态

spfa部分:

void spfa(){    while(!que.empty()){        int now = que.front();        que.pop();        int root = now / base;        int state = now % base;        isVis[root][state] = false;                for (int k = head[root]; k != -1; k = edges[k].next){            int to = edges[k].to, weight = edges[k].length;            if (update(to, state|st[to], mincost[root][state] + weight)                    && state|st[to] == state                    && !isVis[to][state])                isVis[to][state] = true;                que.push(to*base + state);        }    }}



AC代码:

#include<bits/stdc++.h>using namespace std;const int INF = 1e6+10;int n, m, K, endSt, tot;int mincost[55][1<<11], st[55];int dp[1<<11];int head[55];bool vis[55][1<<11];queue<int> que;struct Edge{    int to, length;    int next;    Edge(){}    Edge(int t, int len){        to = t;        length = len;        next = -1;    }}edges[2005];void addEdge(int from, int to, int len){    edges[++tot] = Edge(to, len);    edges[tot].next = head[from];    head[from] = tot;}void input(){    tot = 0;    memset(head, -1, sizeof(head));    memset(vis, false, sizeof(vis));    memset(st, 0, sizeof(st));    scanf("%d%d%d", &n, &m, &K);    for (int i = 0; i < m; i++){        int from, to, len;        scanf("%d%d%d", &from, &to, &len);        addEdge(from, to, len);        addEdge(to, from, len);    }    endSt = 1<<(2*K);    for (int i = 1; i <= n; i++){        for (int j = 0; j < endSt; j++){            mincost[i][j] = INF;        }    }    for (int i = 1; i <= K; i++){        st[i] = 1<<(i-1);        mincost[i][st[i]] = 0;        st[n-i+1] = 1<<(K+i-1);        mincost[n-i+1][st[n-i+1]] = 0;    }    while(!que.empty())        que.pop();}bool check(int state){    int res = 0;    for (int i = 0; state; i++, state>>=1){        res += (state&1)*(i < K ? 1 : -1);    }    return res == 0;}bool update(int root, int state, int weight){    if (weight < mincost[root][state]){        mincost[root][state] = weight;        return true;    }    return false;}void spfa(){    while(!que.empty()){        int now = que.front();        que.pop();        int root = now / 10000;        int state = now % 10000;        vis[root][state] = false;        for (int k = head[root]; k != -1; k = edges[k].next){            int to = edges[k].to, weight = edges[k].length;            if (update(to, state|st[to], mincost[root][state]+weight)                && state == (state|st[to])                && !vis[to][state]){                vis[to][state] = true;                que.push(to*10000+state);            }        }    }}int main(){    int T;    scanf("%d",&T);    while(T--){        input();        for (int state = 0; state < endSt; state++){            for (int root = 1; root <= n; root++){                for (int sub = (state-1)&state; sub; sub = (sub-1)&state){                    mincost[root][state] = min(mincost[root][state],                                               mincost[root][sub|st[root]] + mincost[root][(state-sub)|st[root]]);                }                if (mincost[root][state] < INF){                    que.push(root*10000+state);                    vis[root][state] = true;                }            }            spfa();        }        for (int state = 0; state < endSt; state++){            dp[state] = INF;            for (int root = 1; root <= n; root++){                dp[state] = min(mincost[root][state], dp[state]);            }        }        for (int state = 1; state < endSt; state++){            if (!check(state))                continue;            for (int sub = (state-1)&state; sub; sub = (sub-1)&state){                if (!check(sub))                    continue;                dp[state] = min(dp[state], dp[sub] + dp[state-sub]);            }        }        if (dp[endSt-1] >= INF)            printf("No solution\n");        else            printf("%d\n", dp[endSt-1]);    }    return 0;}


0 0
原创粉丝点击