csu1116 Kingdoms 最小生成树-枚举状态

题目链接:

csu 1116

题意:

有一幅双向图连接N个城市(标号1~n,1表示首都)  每个城市有一个价值W.

地震摧毁了所有道路,现给出可修复的m条道路并给出修复每条道路所需的费用

问在总费用不超过k的情况下,使得  与  首都连通的所有城市  的价值和 最大

解题思路:

点的数量不超过16 ,2^16次方枚举所有城市是否在连通的集合类

再通过kruskal判断这个集合是否合法即可

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{
    int a,b,w;
}edge[128];
int v[18];
int fa[18];
int sum;

void init()
{
    for(int i=0;i<18;i++)
        fa[i]=i;
    sum=0;
}

int Find(int x)
{
    return x==fa[x]?x:fa[x]=Find(fa[x]);
}

int cmp(node a,node b)
{
    return a.w<b.w;
}

int main()
{
    int T,n,m,k;
    int ans;
    int f1,f2;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&k);
        ans=0;
        for(int i=1;i<=n;i++)
            scanf("%d",&v[i]);
        for(int i=0;i<m;i++)
            scanf("%d%d%d",&edge[i].a,&edge[i].b,&edge[i].w);
        sort(edge,edge+m,cmp);                                  //给边排序 保证费用尽量小
        int num=(1<<n)-1;
        for(int i=0;i<=num;i++)
        {
            if(i&1)
            {
                init();
                for(int j=0;j<m;j++)
                    if(i&(1<<edge[j].a-1))
                        if(i&(1<<edge[j].b-1))              //当前边属于当前的点集
                        {
                            f1=Find(edge[j].a);
                            f2=Find(edge[j].b);
                            if(f1!=f2)
                            {
                                fa[f1]=f2;
                                sum+=edge[j].w;
                            }
                        }
                for(int j=1;j<=n;j++)
                    if((i&(1<<j-1))&&Find(j)!=Find(1))        //当前点集有多余的点
                    {
                        sum=k+1;
                        break;
                    }
                if(sum<=k)
                {
                    sum=0;
                    for(int j=1;j<=n;j++)
                        if(i&(1<<j-1))
                            sum+=v[j];
                    if(sum>ans)
                        ans=sum;
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-10 11:32:09

csu1116 Kingdoms 最小生成树-枚举状态的相关文章

HDU4081 Qin Shi Huang&#39;s National Road System【prim最小生成树+枚举】

先求出最小生成树,然后枚举树上的边,对于每条边"分别"找出这条割边形成的两个块中点权最大的两个 1.由于结果是A/B,A的变化会引起B的变化,两个制约,无法直接贪心出最大的A/B,故要通过枚举 2.不管magic road要加在哪里,加的边是否是最小生成树上的边,都会产生环,我们都要选择一条边删掉 注意删掉的边必须是树的环上的边,为了使结果最大,即找出最大的边 3.可以枚举两点,找出边,也可以枚举边,找出点,我是用后者,感觉比较容易写也好理解 #include <cstdio&g

CSU 1116 Kingdoms(枚举最小生成树)

题目链接:http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1116 解题报告:一个国家有n个城市,有m条路可以修,修每条路要一定的金币,现在这个国家只有K个金币,每个城市有一些人,要你求怎么修路使得总的费用在K的范围内,同时使得跟首都连接的城市的人口(包括首都的人口)要最多,问最多的人口是多少. 枚举连接哪些城市,然后分别构造最小生成树. 1 #include<cstdio> 2 #include<cstring> 3 #inclu

CSU 1116 Kingdoms 最小生成树(prim)

由于点数只有16,而点1又必选,暴力枚举选点情况,每次做一个最小生成树 这里用的prim算法,要注意的是存在选取这些点但找不到生成树的情况,需要将之排出 #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<map> using namespace std; const int INF=0x3f3f3f3f; const int max

UVa 10807 Prim(最小生成树+枚举)

10807 - Prim Time limit: 3.000 seconds Problem ? Prim, Prim. Time Limit: 3 seconds Calax Research and Development is a large high tech corporation. They have an antitrust lawsuit on their hands because they are too big. The judge has ordered that the

【算法学习笔记】74. 枚举 状态压缩 填充方案 SJTU OJ 1391 畅畅的牙签袋(改)

一开始想贪心,类似启发式搜索的感觉...后来觉得不行,而且很难写. 不如就枚举.可以通过0到2^W的中的每一个数的二进制形式来对应,第一行每个位置是否作为中心点放入十字格子的情况. 当此处为0时表示不放,1时表示放. 为什么只枚举第一行的所有情况就可以了呢. 因为第一行的情况确定之后,我们可以通过推理先改变第二行某些状态,然后再根据必须把第一行充满,可以确定第二排所有必须放十字块的位置. 生成该状态数之后,调用put函数,然后先影响下一行再通过结果来确定下一行.(这个算法的根基就是,处理每一行的

HDU 5025Saving Tang Monk BFS + 二进制枚举状态

3A的题目,第一次TLE,是因为一次BFS起点到终点状态太多爆掉了时间. 第二次WA,是因为没有枚举蛇的状态. 解体思路: 因为蛇的数目是小于5只的,那就首先枚举是否杀死每只蛇即可. 然后多次BFS,先从起点到第一把钥匙,不能往回走,要用VIS数组标记. 第二次从第一把钥匙走到第二把钥匙. 最后一次从最后一把钥匙走到终点即可. Tips 1: 在每次BFS过程中使用优先队列保证每次是最小步长的状态. Tips2 :使用二进制枚举蛇的状态 Tips3:首先使用DFS判断是否绝对有解,如果无解输出"

最小生成树 + 枚举最小边

Given an undirected weighted graph G, you should find one of spanning trees specified as follows. The graph G is an ordered pair (V, E), where V is a set of vertices {v1, v2, -, vn} and E is a set of undirected edges {e1, e2, -, em}. Each edge e ∈ E

CSU 1541 There is No Alternative (最小生成树+枚举)

题目链接:传送门 题意: 有n个点.m条边.要使n个点所有连起来且要花费最小.问有哪些边是必需要连的. 分析: 要使花费最小肯定是做最小生成树.可是题目要求哪些边是必需要用的.我们能够 这样思考,我们先求一次最小生成树,然后把这些用到的边统计起来,然后依次枚 举这n-1条边.使他们不能用,然后继续做最小生成树,假设最后求的值和第一次 不一样的话那么这条边是肯定要连的. 代码例如以下: #include <iostream> #include <cstdio> #include &l

UVa1151 Buy or Build (最小生成树,枚举子集)

链接:http://bak.vjudge.net/problem/UVA-1151 分析:先在原图上跑一遍MST,得到n-1条边,然后其它的边完全可以抛弃掉,因为它们不会比这n-1条边更优,这样就可以把原图边的数量减少到n-1条,并且得到ans初值. 接下来就是通过枚举套餐子集,生成一个套餐费用c1并且得到若干联通分量,再在这些联通分量基础上跑MST得到最小花费c2,更新答案ans. 1 #include <cstdio> 2 #include <vector> 3 #includ