程序设计思维与实践 Week8 作业 (3/4/数据班)

A - 区间选点 II

题意:
给定一个数轴上的 n 个区间,要求在数轴上选取最少的点使得第 i 个区间 [ai, bi] 里至少有 ci 个点
思路:
使用差分约束,构造不等式组,核心如下:

  • 用sum[i]表示数轴上[0,i]之间的选点的个数。
  • 对于第i个区间,sum[bi]-sum[ai-1]>=ci
  • 0<=sum[i]-sum[i-1]<=1
  • 可以把不等式组转成图跑最长路,ans=sum[bn]

总结:
这道题本来使用的普通版的spfa,但是出现了种种错误,最后咨询了舍友,他使用了
SLF优化,我觉得挺好的,修改代码后顺利通过。
代码:

#include <iostream>
#include <cstdio>
#include <climits>
#include <algorithm>
#include <deque>
using namespace std;
const int N = 50000 + 10;
struct node
{
    int to, next, w;
};
node Edges[10 * N];
int head[N], sum[N], n, a, b, c, tot, mmin, mmax;
bool vis[N];
inline void add(int x, int y, int w)
{
    tot++;
    Edges[tot].to = y;
    Edges[tot].w = w;
    Edges[tot].next = head[x];
    head[x] = tot;
}
void slfspfa(int s)
{
    deque<int> q;
    q.push_back(s);
    sum[s] = 0, vis[s] = true;
    while (!q.empty())
    {
        int x = q.front();
        q.pop_front();
        vis[x] = false;
        for (int i = head[x]; i; i = Edges[i].next)
        {
            int y = Edges[i].to;
            if (sum[y] < sum[x] + Edges[i].w)
            {
                sum[y] = sum[x] + Edges[i].w;
                if (!vis[y])
                {
                    if (!q.empty() && sum[y] >= sum[q.front()])
                        q.push_back(y);
                    else
                        q.push_front(y);
                    vis[y] = true;
                }
            }
        }
    }
}
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d%d%d", &a, &b, &c);
        add(a - 1, b, c);
        mmin = min(mmin, a);
        mmax = max(mmax, b);
    }
    for (int i = 0; i <= mmax; i++)
        sum[i] = -1;
    for (int i = mmin - 1; i < mmax; i++)
    {
        add(i, i + 1, 0);
        add(i + 1, i, -1);
    }
    slfspfa(mmin - 1);
    cout << sum[mmax] << endl;
    //system("pause");
}

B - 猫猫向前冲
题意:
众所周知, TT 是一位重度爱猫人士,他有一只神奇的魔法猫。
有一天,TT 在 B 站上观看猫猫的比赛。一共有 N 只猫猫,编号依次为1,2,3,…,N进行比赛。比赛结束后,Up 主会为所有的猫猫从前到后依次排名并发放爱吃的小鱼干。不幸的是,此时 TT 的电子设备遭到了宇宙射线的降智打击,一下子都连不上网了,自然也看不到最后的颁奖典礼。
不幸中的万幸,TT 的魔法猫将每场比赛的结果都记录了下来,现在他想编程序确定字典序最小的名次序列,请你帮帮他。
思路:
这道题就是拓扑排序,也没啥坑。使用小根堆优先队列即可。
总结:
拓扑排序的代码需要好好掌握。
代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <climits>
#include <queue>
#include <vector>
using namespace std;

const int N = 500 + 10;
struct edge
{
    int v, nxt;
} Edges[N * 2];
int n, m, tot, tot2, a, b;
int indegree[N], head[N], ans[N];
void add(int x, int y)
{
    tot++;
    Edges[tot].v = y;
    Edges[tot].nxt = head[x];
    head[x] = tot;
}
bool topo()
{
    priority_queue<int> q;
    while (!q.empty())
        q.pop();
    for (int i = 1; i <= n; i++)
        if (indegree[i] == 0)
            q.push(-i);
    while (!q.empty())
    {
        int u = -q.top();
        q.pop();
        ans[++tot2] = u;
        for (int i = head[u]; i; i = Edges[i].nxt)
            if (--indegree[Edges[i].v] == 0)
                q.push(-Edges[i].v);
    }
    return tot2 == n;
}
int main()
{
    while (scanf("%d%d", &n, &m) == 2)
    {
        tot = 0;
        tot2 = 0;
        memset(head, 0, sizeof(head));
        memset(indegree, 0, sizeof(indegree));
        for (int i = 1; i <= m; i++)
        {
            scanf("%d%d", &a, &b);
            add(a, b);
            indegree[b]++;
        }
        topo();
        for (int i = 1; i < n; i++)
            printf("%d ", ans[i]);
        printf("%d\n", ans[n]);
    }
    //system("pause");
}

C - 班长竞选

题意:
大学班级选班长,N 个同学均可以发表意见 若意见为 A B 则表示 A 认为 B 合适,意见具有传递性,即 A 认为 B 合适,B 认为 C 合适,则 A 也认为 C 合适 勤劳的 TT 收集了M条意见,想要知道最高票数,并给出一份候选人名单,即所有得票最多的同学,你能帮帮他吗?
思路:
这道题学长讲了思路,主要思路:

  1. 计算强连通分量
  2. 缩点
  3. 计算出度为0的点的ans

总结:
我觉得这个题思路不难,难在代码的小细节,代码逻辑。
需要好好的画个草图,仔细的分析。
代码:

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 5010;
const int maxm = 30020;
int f[maxn], vis[maxn], scc[maxn], color[maxn], degree[maxn];
int n, fcnt, tot1, tot2, tot3, s, scnt, mmax = 0;
int head1[maxn], head2[maxn], head3[maxn], ans[maxn], ano[maxn];
struct Edge
{
    int v, nxt;
} Edges1[maxm], Edges2[maxm], Edges3[maxn];

void init()
{
    tot1 = tot2 = tot3 = scnt = mmax = 0;
    fcnt = -1;
    memset(degree, 0, sizeof(degree));
    memset(head1, -1, sizeof(head1));
    memset(head2, -1, sizeof(head2));
    memset(head3, -1, sizeof(head3));
    memset(vis, 0, sizeof(vis));
    memset(color, 0, sizeof(color));
    memset(scc, 0, sizeof(scc));
    memset(f, 0, sizeof(f));
    memset(ano, 0, sizeof(ano));
    memset(ans, 0, sizeof(ans));
}

void addedge(Edge *Edges, int *head, int u, int v, int &tot)
{
    Edges[tot].v = v;
    Edges[tot].nxt = head[u];
    head[u] = tot++;
}

void dfs1(int x) //逆后序列
{
    vis[x] = 1;
    for (int i = head1[x]; i != -1; i = Edges1[i].nxt)
    {
        int v = Edges1[i].v;
        if (!vis[v])
            dfs1(v);
    }
    f[++fcnt] = x;
}
void dfs2(int x)
{
    color[x] = scnt;
    scc[scnt]++;
    for (int i = head2[x]; i != -1; i = Edges2[i].nxt)
    {
        int v = Edges2[i].v;
        if (color[v] == 0)
            dfs2(v);
    }
}
void dfs3(int x)
{
    vis[x] = 1;
    for (int i = head3[x]; i != -1; i = Edges3[i].nxt)
    {
        int v = Edges3[i].v;
        if (vis[v] == 0)
        {
            ans[s] += scc[v];
            dfs3(v);
        }
    }
}
void Kosaraju()
{
    dfs1(0);
    for (int i = 1; i < n; i++)
    {
        if (!vis[i])
            dfs1(i);
    }
    for (int i = 0; i <= fcnt; i++)
    {
        int x = f[fcnt - i];
        if (color[x] == 0)
        {
            scnt++;
            dfs2(x);
        }
    }
}
void indent()
{
    for (int i = 0; i < n; i++)
    {
        for (int j = head2[i]; j != -1; j = Edges2[j].nxt)
        {
            int v = Edges2[j].v;
            if (color[i] != color[v])
            {
                addedge(Edges3, head3, color[i], color[v], tot3);
                degree[color[v]]++;
            }
        }
    }
}
void answer()
{
    for (int i = 1; i <= scnt; i++)
    {
        if (degree[i] == 0)
        {
            memset(vis, 0, sizeof(vis));
            ans[i] += scc[i] - 1;
            s = i;
            dfs3(i);
            mmax = max(mmax, ans[i]);
        }
    }
    for (int i = 1; i <= scnt; i++)
    {
        if (ans[i] == mmax)
            ano[i] = 1;
    }
}
void print()
{
    printf("%d\n", mmax);
    int flag = 0;
    for (int i = 0; i < n; i++)
    {
        if (ano[color[i]] == 1)
        {
            if (flag == 0)
            {
                printf("%d", i);
                flag++;
            }
            else
                printf(" %d", i);
        }
    }
    cout << endl;
}
int main()
{
    int T;
    cin >> T;
    for (int i = 1; i <= T; i++)
    {
        int m;
        scanf("%d%d", &n, &m);
        init();
        while (m--)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            addedge(Edges1, head1, a, b, tot1);
            addedge(Edges2, head2, b, a, tot2);
        }
        cout << "Case " << i << ": ";
        Kosaraju();
        indent();
        answer();
        print();
    }
    //system("pause");
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
城市应急指挥系统是智慧城市建设的重要组成部分,旨在提高城市对突发事件的预防和处置能力。系统背景源于自然灾害和事故灾难频发,如汶川地震和日本大地震等,这些事件造成了巨大的人员伤亡和财产损失。随着城市化进程的加快,应急信息化建设面临信息资源分散、管理标准不统一等问题,需要通过统筹管理和技术创新来解决。 系统的设计思路是通过先进的技术手段,如物联网、射频识别、卫星定位等,构建一个具有强大信息感知和通信能力的网络和平台。这将促进不同部门和层次之间的信息共享、交流和整合,提高城市资源的利用效率,满足城市对各种信息的获取和使用需求。在“十二五”期间,应急信息化工作将依托这些技术,实现动态监控、风险管理、预警以及统一指挥调度。 应急指挥系统的建设目标是实现快速有效的应对各种突发事件,保障人民生命财产安全,减少社会危害和经济损失。系统将包括预测预警、模拟演练、辅助决策、态势分析等功能,以及应急值守、预案管理、GIS应用等基本应用。此外,还包括支撑平台的建设,如接警中心、视频会议、统一通信等基础设施。 系统的实施将涉及到应急网络建设、应急指挥、视频监控、卫星通信等多个方面。通过高度集成的系统,建立统一的信息接收和处理平台,实现多渠道接入和融合指挥调度。此外,还包括应急指挥中心基础平台建设、固定和移动应急指挥通信系统建设,以及应急队伍建设,确保能够迅速响应并有效处置各类突发事件。 项目的意义在于,它不仅是提升灾害监测预报水平和预警能力的重要科技支撑,也是实现预防和减轻重大灾害和事故损失的关键。通过实施城市应急指挥系统,可以加强社会管理和公共服务,构建和谐社会,为打造平安城市提供坚实的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值