Gym-101908 J. Joining Capitals, 洛谷P6192 (最小斯坦纳树)

 Joining Capitals题目大意:

给你n个点k个特殊点他们的坐标,求包含k个特殊点的点集的最小代价

且k个特殊点必须作为叶子节点

代价的计算为两点的欧几里德距离

题目思路:

我们用dp[state][i]表示i为根时,选取的特殊点的状态为state时的最小代价

第一类转移我们可以直接枚举子集s1,s2

dp[state][i] = max(dp[state][i],dp[s1][i]+dp[s2][i])

这里用到了二进制下枚举子集的一种方法,所以不必暴力枚举

第二类转移我们枚举要拓展的点new,注意这里new是要作为根节点的,但特殊点只能做叶子节点

所以在转移时要加限定条件new>m

因为距离(代价)可以直接用欧几里德距离求得,所以这里不必再写最短路算法

CODE:

struct Node
{
    double x, y;
} a[maxn];
int n, m;
double dp[1 << 12][200], dis[200][200];
double DIS(int x, int y)
{
    return sqrt((a[x].x - a[y].x) * (a[x].x - a[y].x) + (a[x].y - a[y].y) * (a[x].y - a[y].y));
}
int main()
{
    n = read(), m = read();
    for(int i = 1 ; i <= n ; i++) cin >> a[i].x >> a[i].y;
    rep(i, 0, 1 << 11) rep(j, 0, n) dp[i][j] = 100000000;
    rep(i, 1, m) dp[1 << (i - 1)][i] = 0;
    rep(i, 1, n) rep(j, 1, n)dis[i][j] = DIS(i, j);
    for(int i = 1 ; i < (1 << m) ; i++)
    {
 
        for(int j = (i - 1)&i ; j ; j = (j - 1)&i)
            for(int k = 1 ; k <= n ; k++)
                dp[i][k] = min(dp[i][k], dp[j][k] + dp[i ^ j][k]);
 
        for(int j=1 ;j<=n ;j++)
            for(int k=1 ;k<=n ;k++) 
                if(k>m)dp[i][k] = min(dp[i][k],dp[i][j]+dis[k][j]);
 
    }
    double ans = 100000000;
    rep(i,1+m,n)if(dp[(1<<m)-1][i]<ans) ans = dp[(1<<m)-1][i];
    printf("%.5lf\n",ans );
 
    return  0 ;
}
View Code

洛谷P6192最小斯坦纳树 模板题

不过在进行第二类转移的时候要加最短路算法进行转移

 个人认为这里最短路算法是用来优化转移的

拿这个题来说,我们完全可以Flody预处理出所有点的距离之后采用跟上面的题一样的n^2的转移

但是如果用spfa或者dijkstra来转移的话,在面对一些数据时肯能效率会更高

CODE_flody:

int n, m, k, head[maxn], cnt;
struct node {
    int u, v, w, next;
} e[maxn];
void add(int u, int v, int w) {
    e[cnt].u = u, e[cnt].v = v, e[cnt].w = w;
    e[cnt].next = head[u], head[u] = cnt++;
}
int t[maxn];
int dp[1 << 12][102];
int dis[102][102];
void Flody() {
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            for (int k = 1; k <= n; k++) {
                dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
            }
        }
    }
}
int main() {
    n = read(), m = read(), k = read();
    mst(head, -1), mst(dis, inf);
    rep(i, 1, n) dis[i][i] = 0;
    for (int i = 1; i <= m; i++) {
        int u, v, w;
        u = read(), v = read(), w = read();
        dis[v][u] = dis[u][v] = min(dis[u][v], w);
        add(u, v, w), add(v, u, w);
    }
    Flody();
    rep(i, 1, k) t[i] = read();
    rep(i, 0, 1 << 11) rep(j, 0, 101) dp[i][j] = inf;
    rep(i, 1, k) dp[1 << (i - 1)][t[i]] = 0;

    for (int i = 1; i < (1 << k); i++) {
        for (int j = i; j; j = (j - 1) & i) {
            for (int k = 1; k <= n; k++) {
                dp[i][k] = min(dp[i][k], dp[j][k] + dp[j ^ i][k]);
            }
        }

        for (int j = 1; j <= n; j++) {
            for (int k = 1; k <= n; k++) {
                dp[i][k] = min(dp[i][k], dp[i][j] + dis[j][k]);
            }
        }
    }
    out(dp[(1 << k) - 1][t[1]]);
    return 0;
}
View Code

 

CODE_spfa:

int n, m, k, head[maxn], cnt;
struct node {
    int u, v, w, next;
} e[maxn];
void add(int u, int v, int w) {
    e[cnt].u = u, e[cnt].v = v, e[cnt].w = w;
    e[cnt].next = head[u], head[u] = cnt++;
}
int t[maxn];
int dp[1 << 12][102];

queue<int> q;
int vis[maxn];
void spfa(int S) {
    while (q.size()) {
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for (int i = head[u]; ~i; i = e[i].next) {
            int v = e[i].v;
            if (dp[S][v] > dp[S][u] + e[i].w) {
                dp[S][v] = dp[S][u] + e[i].w;
                if (vis[v] == 0) {
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
    }
}
int main() {
    n = read(), m = read(), k = read();
    mst(head, -1);
    for (int i = 1; i <= m; i++) {
        int u, v, w;
        u = read(), v = read(), w = read();
        add(u, v, w), add(v, u, w);
    }
    rep(i, 1, k) t[i] = read();
    rep(i, 0, 1 << 11) rep(j, 0, 101) dp[i][j] = inf;
    rep(i, 1, k) dp[1 << (i - 1)][t[i]] = 0;

    for (int i = 1; i < (1 << k); i++) {

        for (int j = i; j; j = (j - 1) & i) {
            for (int k = 1; k <= n; k++) {
                dp[i][k] = min(dp[i][k], dp[j][k] + dp[j ^ i][k]);
                if (dp[i][k] != inf)
                    q.push(k), vis[k] = 1;
            }
        }
        spfa(i);
    }
    out(dp[(1 << k) - 1][t[1]]);
    return 0;
}
View Code

 

posted @ 2021-04-28 14:11  UpMing  阅读(104)  评论(0编辑  收藏  举报