CSU 1116 Kingdoms(Kruskal)(枚举)

115 篇文章 0 订阅
15 篇文章 0 订阅

Kingdoms

Description
A kingdom has n cities numbered 1 to n, and some bidirectional roads connecting cities. The capital is always city 1.
After a war, all the roads of the kingdom are destroyed. The king wants to rebuild some of the roads to connect the cities, but unfortunately, the kingdom is running out of money. The total cost of rebuilding roads should not exceed K.
Given the list of m roads that can be rebuilt (other roads are severely damaged and cannot be rebuilt), the king decided to maximize the total population in the capital and all other cities that are connected (directly or indirectly) with the capital (we call it “accessible population”), can you help him?
Input
The first line of input contains a single integer T (T<=20), the number of test cases.
Each test case begins with three integers n(4<=n<=16), m(1<=m<=100) and K(1<=K<=100,000).
The second line contains n positive integers pi (1<=pi<=10,000), the population of each city.
Each of the following m lines contains three positive integers u, v, c (1<=u,v<=n, 1<=c<=1000), representing a destroyed road connecting city u and v, whose rebuilding cost is c.
Note that two cities can be directly connected by more than one road, but a road cannot directly connect a city and itself.
Output
For each test case, print the maximal accessible population.

Sample Input
2
4 6 6
500 400 300 200
1 2 4
1 3 3
1 4 2
4 3 5
2 4 6
3 2 7
4 6 5
500 400 300 200
1 2 4
1 3 3
1 4 2
4 3 5
2 4 6
3 2 7
Sample Output
1100
1000

题意:有n个城市,每个城市都有一些人,给你一些要修复的路和修复每条路需要的花费,问你在花费不超过K的情况下,能到达城市1的最多人数

思路:点的数量不超过16 ,直接2^16枚举所有的城市,然后Kruskal判断是否合法即可
二进制的2^x位为1表示选择第x+1个城市

代码:

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

struct node
{
    int u,v,w;
    bool operator < (const node&A)const
    {
        return w<A.w;
    }
} E[110];
int n,m,k;
int num[18],pre[18];

void init()
{
    for(int i=1; i<=n; ++i)
        pre[i]=i;
}

int Find(int x)
{
    if(x==pre[x])
        return x;
    return pre[x]=Find(pre[x]);
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1; i<=n; ++i)
            scanf("%d",&num[i]);
        for(int i=0; i<m; ++i)
            scanf("%d%d%d",&E[i].u,&E[i].v,&E[i].w);
        sort(E,E+m);
        int ans=0;
        for(int i=1; i<=((1<<n)-1); ++i)
        {
            if(!(i&1))//去除不含1的情况
                continue;
            init();
            int cost=0;
            for(int j=0; j<m; ++j)
            {
                int u=E[j].u,v=E[j].v,w=E[j].w;
                int fx=Find(u),fy=Find(v);
                if((i&(1<<(u-1)))&&(i&(1<<(v-1)))&&(fx!=fy))
                {
                    pre[fx]=fy;
                    cost+=w;
                }
                if(cost>k)
                    break;
            }
            for(int j=2; j<=n; ++j)//检查预定的每一个点是否与1相连
            {
                if(((1<<(j-1))&i)&&(Find(j)!=Find(1)))
                {
                    cost=k+1;
                    break;
                }
            }
            if(cost<=k)
            {
                int sum=0;
                for(int j=1; j<=n; ++j)
                {
                    if(i&(1<<(j-1)))
                        sum+=num[j];
                }
                ans=max(ans,sum);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}



总结:一看就是枚举,我的想法是先来个最短路求出1到其他各个城市的最短距离,然后dfs枚举每个城市,结果TLE了。。。(很有可能是太暴力了)

我觉得状压比起我的方法的好处就是多了很多剪枝,这就节省了时间。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值