刷题记录(NC20568 [SCOI2012] 滑雪与时间胶囊)

NC20568 [SCOI2012] 滑雪与时间胶囊

题目链接

关键点:

1、题目要求求出在访问的景点最多的情况下,所能花费的最短距离和到达的最多的景点数量。

2、对于求能访问的最多景点,题目定的起点为1,那么就直接从1点开始dfs,看其所能到达的边,然后将其记录下来,并记录总个数。总个数即为访问的最多的景点数。

3、先考虑在所有点均为双向边的连接情况下,所能到达的最短距离,我们可以用最小生成树prim或者Kruskal算法来求解,我们这里考虑使用Kruskal来计算,但是这里有一个限制条件,即边有可能为单向的,如果我们直接对边的长度进行排序后,然后找最小边插入,那么我们有可能会造成该树的所有结点并不能均到达,即不满足在点最多的情况下找距离最小的情况。

4、因此我们要先挑那些高的景点(一条边的两点,那么该边的高度即为两点中高度较低的那个高度),在高度均相同的情况下再挑距离小的边,这样排序来选边

5、还有该边的两点要保证x能够到达,即在dfs中被标记的点

6、根据边的长度范围和边的数量,最短距离可能会很大,因此答案要开long long

完整代码:

# include <bits/stdc++.h>
using namespace std;
struct ty2{
    int x, y, h, len;
}bian[1000000+10];
int n, m, cnt, num;
int fa[100000+10], h[100000+10], vis[100000+10], head[100000+10];
struct ty{
    int t, next, len;
}edge[2000000+10];
void addedge(int x, int y, int len)
{
    edge[++num].t = y;
    edge[num].len = len;
    edge[num].next = head[x];
    head[x] = num;
}
void dfs(int x)
{
    vis[x] = 1;
    cnt++;
    for (int i=head[x]; i!=-1; i = edge[i].next)
    {
        int y = edge[i].t;
        if (vis[y]) continue;
        dfs(y);
    }
}
int find(int x)
{
    return fa[x]==x? x: fa[x] = find(fa[x]);
}
bool cmp(ty2 t1, ty2 t2)
{
    if (t1.h == t2.h) return t1.len<t2.len;
    else
        return t1.h>t2.h;
}
int main()
{
    memset(head, -1, sizeof(head));
    cin>>n>>m;
    for (int i=1; i<=n; i++)
        cin>>h[i];
    for (int i=1; i<=m; i++)
    {
        int x, y, len;
        cin>>x>>y>>len;
        bian[i].x = x;
        bian[i].y = y;
        bian[i].len = len;
        bian[i].h = min(h[x], h[y]);
        if (h[x]>=h[y])
            addedge(x, y, len);
        if (h[y]>=h[x])
            addedge(y, x, len);
    }
    dfs(1);
    sort(bian+1, bian+1+m, cmp);
    long long ans = 0;
    for (int i=1; i<=n; i++) fa[i] = i;
    for (int i=1; i<=m; i++)
    {
        int x = bian[i].x, y = bian[i].y;
        if (!vis[x] || !vis[y]) continue;
        int fx = find(x), fy = find(y);
        if (fx!=fy)
        {
            ans += bian[i].len;
            fa[fx] = fy;
        }
    }
    cout<<cnt<<" "<<ans<<endl;
    return 0;
}

中描述了一个幼儿园里分配糖果的问题,每个小朋友都有自己的要求。问题的输入包括两个整数NN和KK,表示幼儿园里的小朋友数量和要满足的要求数量。接下来的KK行表示小朋友们的要求,每行有三个数字,XX,AA,BB。如果X=1,表示第AA个小朋友分到的糖果必须和第BB个小朋友分到的糖果一样多;如果X=2,表示第AA个小朋友分到的糖果必须少于第BB个小朋友分到的糖果;如果X=3,表示第AA个小朋友分到的糖果必须不少于第BB个小朋友分到的糖果;如果X=4,表示第AA个小朋友分到的糖果必须多于第BB个小朋友分到的糖果;如果X=5,表示第AA个小朋友分到的糖果必须不多于第BB个小朋友分到的糖果。这个问题可以被看作是一个差分约束系统的问题。 具体地说,可以使用差分约束系统来解决这个问题。差分约束系统是一种通过给变量之间的关系添加约束来求解最优解的方法。对于这个问题,我们需要根据小朋友们的要求建立约束条件,并通过解决这个约束系统来得出最小的糖果数量。 在问题的输入中,X的取值范围为1到5,分别对应不同的关系约束。根据这些约束,我们可以构建一个差分约束图。图中的节点表示小朋友,边表示糖果数量的关系。根据不同的X值,我们可以添加相应的边和权重。然后,我们可以使用SPFA算法(Shortest Path Faster Algorithm)来求解这个差分约束系统,找到满足所有约束的最小糖果数量。 需要注意的是,在读取输入时需要判断X和Y是否合法,即是否满足X≠Y。如果X=Y,则直接输出-1,因为这种情况下无法满足约束条件。 综上所述,为了满足每个小朋友的要求,并且满足所有的约束条件,我们可以使用差分约束系统和SPFA算法来求解这个问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【差分约束系统】【SCOI2011】糖果 candy](https://blog.csdn.net/jiangzh7/article/details/8872699)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [P3275 [SCOI2011]糖果(差分约束板子)](https://blog.csdn.net/qq_40619297/article/details/88678605)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值