CSU 1116 Kingdoms

  原题链接:http://122.207.68.93/OnlineJudge/problem.php?id=1116

  由于n比较小,直接枚举,然后对于每一个状态用最小生成树算法验证即可,感觉是水过去的,复杂度O(2n*n*m)。(有状压DP做法?)

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 20

struct Node
{
    int u, v, w;
}e[105];

int n, m, k, p[N], ans, f[N];

bool cmp(Node a, Node b)
{
    return a.w < b.w;
}

int find(int x)
{
    return f[x] == x ? x : (f[x] = find(f[x]));
}

bool ok(int cur)
{
    int tot = 0;
    for(int i = 0; i < n; i++) f[i] = i;
    for(int i = 0; i < m; i++)
    {
        if(((cur>>e[i].u)&1) && ((cur>>e[i].v)&1))
        {
            int x = find(e[i].u);
            int y = find(e[i].v);
            if(x != y)
            {
                if(x > y)
                    f[x] = y;
                else 
                    f[y] = x;
                tot += e[i].w;
            }
        }
    }
    for(int i = 0; i < n; i++) // 所有要验证的点都必须和capital在同一个连通分量里面
        if((cur>>i)&1 && find(i) != 0) return false;
    return tot <= k;
}

int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d%d", &n, &m, &k);
        for(int i = 0; i < n; i++)
            scanf("%d", &p[i]);
        Node tmp;
        for(int i = 0; i < m; i++)
        {
            scanf("%d%d%d", &tmp.u, &tmp.v, &tmp.w);
            tmp.u--; tmp.v--;
            e[i] = tmp;
        }
        sort(e, e+m, cmp);
        ans = -1;
        for(int i = 1; i < (1 << n); i++)
        {
            if(ok(i))
            {
                int tot = 0;
                for(int j = 0; j < n; j++)
                {
                    if((i >> j) & 1)
                        tot += p[j];
                }
                ans = max(ans, tot);
            }
        }
        printf("%d
", ans);
    }
    return 0;
}
View Code

  

原文地址:https://www.cnblogs.com/huangfeihome/p/3429118.html