• HDU 3311 Dig The Wells


    HDU_3311

        我表示完全没看懂题意……膜拜看懂题意的各位大神,附一份“偷”来的题意:

        【题目大意】

        给定N个寺庙,和M个另外的地方。

        然后给定点权,表示在这个点挖水井需要的代价。

        再给定边权,为建造无向边i,j的代价。

        然后求怎样弄最小的代价使得前N个点,就是寺庙都能得到水。

        这个和一般的斯坦纳树的题目不同的地方在于挖井要加点权,但是仔细分析一下不难发现,如果1-N作为斯坦纳树的叶子节点一共有两种状态,要么挖井要么不挖井,而其他点做为叶子节点只有一种状态,就是必须挖井,否则由于这个节点就可以被删去就一定不会是最优的方案。在dp之前如果将这些叶子节点的状态都初始化好的话,后面的内容就和普通的斯坦纳树的题目就没有什么区别了,只需要考虑边权即可,另外最后合并连通块dp的时候要判断一下当前集合内是否有水,而且要用两个有水的点集合成当前这个点集。

        由于要判一个连通块内有没有水,所以要多开一个二进制位表示有没有水。

        另外推荐一个感觉讲斯坦纳树讲得不错的博客:http://endlesscount.blog.163.com/blog/static/821197872012525113427573/

    #include<stdio.h>
    #include<string.h>
    #define MAXD 1010
    #define MAXM 10010
    #define ST 74
    #define MAXQ 74010
    #define INF 0x3f3f3f3f
    const int Q = 74000;
    int N, M, P, first[MAXD], e, next[MAXM], v[MAXM], w[MAXM];
    int bit[MAXD], q[MAXQ], front, rear, inq[MAXD][ST];
    int f[MAXD][ST], dp[ST];
    void add(int x, int y, int z)
    {
        v[e] = y, w[e] = z;
        next[e] = first[x], first[x] = e ++;
    }
    void init()
    {
        int i, x, y, z;
        memset(f, 0x3f, sizeof(f));
        memset(bit, 0, sizeof(bit));
        for(i = 1; i <= N + M; i ++)
        {
            if(i <= N) bit[i] = 1 << i - 1;
            scanf("%d", &z);
            if(i <= N) f[i][bit[i]] = 0, f[i][bit[i] | 1 << N] = z;
            else f[i][1 << N] = z;
        }
        memset(first, -1, sizeof(first));
        e = 0;
        for(i = 0; i < P; i ++)
        {
            scanf("%d%d%d", &x, &y, &z);
            add(x, y, z), add(y, x, z);
        }
    }
    int Min(int x, int y)
    {
        return x < y ? x : y;
    }
    void spfa()
    {
        int i, x, st, y, nst;
        while(front != rear)
        {
            x = q[front] & 1023, st = q[front] >> 10;
            inq[x][st] = 0;
            ++ front > Q ? front = 0 : 0;
            for(i = first[x]; i != -1; i = next[i])
            {
                y = v[i], nst = st | bit[y];
                if(f[x][st] + w[i] < f[y][nst])
                {
                    f[y][nst] = f[x][st] + w[i];
                    if(st == nst && !inq[y][nst])
                    {
                        q[rear ++] = nst << 10 | y, inq[y][nst] = 1;
                        rear > Q ? rear = 0 : 0;
                    }
                }
            }
        }
    }
    void solve()
    {
        int i, j, k, nn = 1 << N + 1;
        front = rear = 0;
        memset(inq, 0, sizeof(inq));
        for(i = 0; i < nn; i ++)
        {
            for(j = 1; j <= N + M; j ++)
            {
                for(k = i - 1 & i; k; k = k - 1 & i)
                    f[j][i] = Min(f[j][i], f[j][k | bit[j]] + f[j][i - k | bit[j]]);
                if(f[j][i] < INF)
                {
                    q[rear ++] = i << 10 | j, inq[j][i] = 1;
                    rear > Q ? rear = 0 : 0;
                }
            }
            spfa();
        }
    
        memset(dp, 0x3f, sizeof(dp));
        for(i = 0; i < nn; i ++)
            for(j = 1; j <= N + M; j ++)
                dp[i] = Min(dp[i], f[j][i]);
        for(i = 0; i < nn; i ++)
            if(i & 1 << N)
            {
                for(j = i - 1 & i; j; j = j - 1 & i)
                    if(j & 1 << N)
                        dp[i] = Min(dp[i], dp[j] + dp[i - j | 1 << N]);
            }
        printf("%d\n", dp[(1 << N + 1) - 1]);
    }
    int main()
    {
        while(scanf("%d%d%d", &N, &M, &P) == 3)
        {
            init();
            solve();
        }
        return 0;
    }
  • 相关阅读:
    将博客搬至CSDN
    JAVA代码备注
    清空数据库SQL
    实战ASP.NET访问共享文件夹(含详细操作步骤)
    我希望我知道的七个JavaScript技巧 译(转)
    ASP.NET获取客户端网卡使用的MAC地址信息
    JS中offsetTop、clientTop、scrollTop、offsetTop各属性介绍
    JS屏幕距离参数
    jQuery插件开发精品教程,让你的jQuery提升一个台阶
    jQuery编程的最佳实践
  • 原文地址:https://www.cnblogs.com/staginner/p/2620945.html
Copyright © 2020-2023  润新知