• UVA12507 Kingdoms 题解


    题目翻译(管理顺便把翻译过一下呗/kel)

    题目传送

    更好的阅读体验?

    Solution

    发现 (n) 的数据范围很小,考虑状压。

    但我不会转移方程,于是结合一点 SPFA 和 Prim 的思想来搞。

    (f_{i}) 表示到达 (i) 状态所需的最少的资金。状态 (i) 表示,如果 (i) 的第 (x) 位为 (1),表示城市 (x)(1) 相连通。

    把每个状态看成点跑 SPFA,显然初始状态为 (f_1 = 0)

    怎么转移?

    我们可以让前一个状态选中的所有点向周围能到达的所有点扩展,从而到达一个新状态。

    枚举所有是 (1) 的二进制位,假设是第 (x) 位,如果有一条边 ((x,v)) 就可以尝试转移。转移方程如下:

    [f_{i | (1<<v)} = min{f_{i} + dis(x,v) }(i&(1<<x)=1) ]

    按照 SPFA 的松弛操作来跑即可。

    数据比较弱,当前是最优解。

    Code

    /*
    Work by: Suzt_ilymics
    Problem: 不知名屑题
    Knowledge: 垃圾算法
    Time: O(能过)
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define LL long long
    #define orz cout<<"lkp AK IOI!"<<endl
    
    using namespace std;
    const int MAXN = 1e5+5;
    const int INF = 1e9+7;
    const int mod = 1e9+7;
    
    struct edge {
        int to, w, nxt;
    }e[300 << 1];
    int head[20], num_edge = 1;
    
    int T, n, m, K;
    int val[20], f[MAXN];
    bool vis[MAXN];
    queue<int> q;
    
    int read(){
        int s = 0, f = 0;
        char ch = getchar();
        while(!isdigit(ch))  f |= (ch == '-'), ch = getchar();
        while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
        return f ? -s : s;
    }
    
    void add_edge(int from, int to, int w) { e[++num_edge] = (edge){to, w, head[from]}, head[from] = num_edge; }
    
    void SPFA() {
        memset(f, 0x3f, sizeof f);
        f[1] = 0;
        q.push(1), vis[1] = true;
        while(!q.empty()) {
            int S = q.front(); q.pop();
            vis[S] = false;
            for(int i = 1; i <= n; ++i) {
                if(S & (1 << (i - 1))) {
                    for(int j = head[i]; j; j = e[j].nxt) {
                        int v = e[j].to, now_ = (S | (1 << v - 1));
                        if(f[now_] > f[S] + e[j].w) {
                            f[now_] = f[S] + e[j].w;
                            if(!vis[now_]) q.push(now_), vis[now_] = true;
                        }
                    }
                }
            }
        }
    }
    
    int main()
    {
        T = read();
        while(T--) {
            memset(head, false, sizeof head);
            num_edge = 1;
            n = read(), m = read(), K = read();
            for(int i = 1; i <= n; ++i) val[i] = read();
            for(int i = 1, u, v, w; i <= m; ++i) {
                u = read(), v = read(), w = read();
                add_edge(u, v, w), add_edge(v, u, w);
            }
            SPFA();
            int Ans = -1;
            for(int i = 1; i < (1 << n); ++i) {
    //            cout<<i<<" "<<f[i]<<"
    ";
                if(f[i] > K) continue;
                int sum = 0;
                for(int j = 1; j <= n; ++j) if(i & (1 << j - 1)) sum += val[j];
                Ans = max(Ans, sum);
            }
            printf("%d
    ", Ans);
        }
        return 0;
    }
    
  • 相关阅读:
    呼叫中心获取sip数据报文
    【代码总结】GD库中简单的验证码
    【代码学习】PHP中GD库的使用
    【漏洞详解】文件包含漏洞
    讲两道常考的阶乘算法题
    如何高效解决接雨水问题
    如何判定括号合法性
    二分查找高效判定子序列
    一道数组去重的算法题把东哥整不会了
    如何高效寻找素数
  • 原文地址:https://www.cnblogs.com/Silymtics/p/15013782.html
Copyright © 2020-2023  润新知