Vj程序设计作业H7

A : 卖菜

问题描述

  在一条街上有 n 个卖菜的商店,按 1 至 n 的顺序排成一排,这些商店都卖一种蔬菜。
  第一天,每个商店都自己定了一个价格。店主们希望自己的菜价和其他商店的一致,第二天,每一家商店都会根据他自己和相邻商店的价格调整自己的价格。具体的,每家商店都会将第二天的菜价设置为自己和相邻商店第一天菜价的平均值(用去尾法取整)。
  注意,编号为 1 的商店只有一个相邻的商店 2,编号为 n 的商店只有一个相邻的商店 n-1,其他编号为 i 的商店有两个相邻的商店 i-1 和 i+1。
  给定第一天各个商店的菜价,请计算第二天每个商店的菜价。

输入格式

输入的第一行包含一个整数 n,表示商店的数量。
  第二行包含 n 个整数,依次表示每个商店第一天的菜价。

输出格式

输出一行,包含 n 个正整数,依次表示每个商店第二天的菜价。

样例输入

8
4 1 3 1 6 5 17 9

样例输出

2 2 1 3 4 9 10 13

数据规模和约定

对于所有评测用例,2 ≤ n ≤ 1000,第一天每个商店的菜价为不超过 10000 的正整数。

解答

#include <bits/stdc++.h>

using namespace std;

int main()
{
    int n;
    cin >> n;
    int a[n + 1] = {0};
    int b[n + 1] = {0};
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    for (int i = 1; i <= n; i++)
    {
        if (i == 1)
        {
            b[i] = (a[i] + a[i + 1]) / 2;
        }
        else if (i == n)
        {
            b[i] = (a[i] + a[i - 1]) / 2;
        }
        else
        {
            b[i] = (a[i] + a[i + 1] + a[i - 1]) / 3;
        }
        cout << b[i] << " ";
    }

    cout << endl;
 
    return 0;
}

B : 买菜

问题描述

  小 H 和小 W 来到了一条街上,两人分开买菜,他们买菜的过程可以描述为,去店里买一些菜然后去旁边的一个广场把菜装上车,两人都要买 n 种菜,所以也都要装 n 次车。具体的,对于小 H 来说有 n 个不相交的时间段[a1​,b1​],[a2​,b2​]...[an​,bn​]在装车,对于小 W 来说有 n 个不相交的时间段[c1​,d1​],[c2​,d2​]...[cn​,dn​]在装车。其中,一个时间段[s, t]表示的是从时刻 s 到时刻 t 这段时间,时长为 t-s。
  由于他们是好朋友,他们都在广场上装车的时候会聊天,他们想知道他们可以聊多长时间。

输入格式

输入的第一行包含一个正整数 n,表示时间段的数量。
  接下来 n 行每行两个数ai​,bi​,描述小 H 的各个装车的时间段。
  接下来 n 行每行两个数ci​,di​,描述小 W 的各个装车的时间段。

输出格式

输出一行,一个正整数,表示两人可以聊多长时间。

样例输入

4
1 3
5 6
9 13
14 15
2 4
5 7
10 11
13 14

样例输出

3

数据规模和约定

对于所有的评测用例,1 ≤ n ≤ 2000, ai​<bi​<ai+1​,ci​<di​<ci+1​,对于所有的 i(1 ≤ i ≤ n)有,1 ≤ ai​,bi​,ci​,di​ ≤ 1000000。

解答

#include<bits/stdc++.h>
using namespace std;
int a[1000001] = {0};
int main(){
    int n;
    cin >> n;
    int sum = 0;
    for (int i = 1; i <= n;i++){
        int x, y;
        cin >> x >> y;
        for (int j = x; j < y;j++){
            a[j] = 1;
        }
        a[y] = 2;
    }
    for (int i = 1; i <= n;i++){
        int x, y;
        cin >> x >> y;
        for (int j = x; j <= y;j++){
            if(a[j]==1 and j!=y){
                sum++;
            }
            // if(a[j] == 2){
            //     sum--;
            // }
        }
    }
    cout << sum << '\n';
    return 0;
}

C : 穿越虫洞

问题描述

小 H 有n个秘密基地(编号 1 到 n ),n 个秘密基地之间有 m 条双向路径和 w 个单向时空隧道,通过路径需要消耗一定的时间Ti​,而通过时空隧道可以使时光倒流Tj​,现在小 H 想知道他能否从某一秘密基地出发,通过路径和时空隧道回到过去(即回到出发的秘密基地且该时刻要早于出发时间)。

输入格式

第1行,一个整数 F,表示测试用例的数量
接下来对于每一个测试用例,输入格式如下
第1行,三个空格分隔的整数n,m,w
第2到 m+1 行,三个空格分隔的数字 s,e,t,表示 s,e 之间存在双向道路,通行需要消耗t,允许两点间存在多条路径
第m+2到m+w+1行三个空间分隔的数字 s,e,t,表示存在从 s 到 e 的单向时空隧道,穿过时空隧道时光倒流 t

输出格式

对于每个测试用例,如果小 H 能回到过去则输出 YES,否则输出 NO
每个测试用例的输出占一行

样例输入

2
3 3 1
1 2 2
1 3 4
2 3 1
3 1 3
3 2 1
1 2 3
2 3 4
3 1 8

样例输出

NO
YES

数据规模和约定

1≤n≤500,1≤m≤4×104,1≤w≤200
1≤Ti​,Tj​≤104

解答

#include <bits/stdc++.h>

using namespace std;
int dis[510][510];
#define inf 1e8

void FF(int n)
{
    for (int k = 1; k <= n; k++)
    {
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
            }
        }
    }
}
int main()
{
    int F;
    cin >> F;
    for (int ii = 1; ii <= F; ii++)
    {
        int n, m, w;
        cin >> n >> m >> w;
        int s, e, t;
        // 初始化
        for (int i = 0; i <= n; i++)
        {
            for (int j = 0; j <= n; j++)
            {
                if (i == j)
                {
                    dis[i][j] = 0;
                }
                else
                {
                    dis[i][j] = inf;
                }
            }
        }
        for (int x = 0; x < m; x++)
        {
            cin >> s >> e >> t;
            dis[s][e] = t;
            dis[e][s] = t;
        }
        for (int x = 0; x < w; x++)
        {
            cin >> s >> e >> t;
            dis[s][e] = -t;
        }
        FF(n);
        int u = 0;
        for (; u <= n; u++)
        {
            if (dis[u][u] < 0)
            {
                cout << "YES" << endl;
                break;
            }
        }
        if (u > n)
        {
            cout << "NO" << endl;
        }
    }
 
    return 0;
}

D : 差旅花费

问题描述

有 n 个车站,其中 1 号车站为始发站,现有 n-1 个人,你需要安排他们分别去往除始发站以外的 n-1 个车站,然后返回始发站。交通系统的所有路径均为单向路径,连接两个不同的车站,每经过一条路径需要交纳一定的费用,你能求出总花费的最低金额嘛

输入格式

第一行一个整数 T,表示测试用例的个数。
对于每个测试用例,输入格式如下
第一行两个整数 n,m,分别表示车站的数量和车站之间的单向路径数。
接下来 m 行,每行三个数 s,e,c,表示存在从 s 到 e 的单向路径,花费为 c

输出格式

对于每个测试用例,输出其总花费的最低金额,每个测试用例的输出占一行。

样例输入

2
2 2
1 2 13
2 1 33
4 6
1 2 10
2 1 60
1 3 20
3 4 10
2 4 5
4 1 50

样例输出

46
210

数据规模和约定

1<=n,m<=1000000
价格 c 为正整数,且保证其总和小于 1000000000

解答

#include <bits/stdc++.h>

using namespace std;
#define N 1000000
#define pa pair<int, int>
#define inf 1e8
int tot, tot2;
int dis[N], vis[N];
int point[N], V[N], W[N], nxt[N];
int dis2[N], vis2[N];
int point2[N], V2[N], W2[N], nxt2[N];
void add(int x, int y, int z)
{
    tot++;
    nxt[tot] = point[x];
    point[x] = tot;
    V[tot] = y;
    W[tot] = z;

    tot2++;
    nxt2[tot2] = point2[y];
    point2[y] = tot2;
    V2[tot2] = x;
    W2[tot2] = z;
}
void init()
{
    for (int i = 0; i < N; i++)
    {
        point[i] = 0;
        point2[i] = 0;
        W[i] = 0;
        W2[i] = 0;
        V[i] = 0;
        V2[i] = 0;
        nxt[i] = 0;
        nxt2[i] = 0;
        dis[i] = 0;
        dis2[i] = 0;
        vis[i] = 0;
        vis2[i] = 0;
        tot = 0;
        tot2 = 0;
    }
}
void dj(int s, int n)
{
    priority_queue<pa, vector<pa>, greater<pa>> q;
    for (int i = 1; i <= n; i++)
    {
        dis[i] = inf;
        vis[i] = 0;
    }
    dis[s] = 0;
    q.push(make_pair(0, s));
    while (!q.empty())
    {
        int x = q.top().second;
        q.pop();
        if (vis[x])
        {
            continue;
        }
        vis[x] = 1;
        for (int i = point[x]; i; i = nxt[i])
        {
            if (dis[V[i]] > dis[x] + W[i])
            {
                dis[V[i]] = dis[x] + W[i];
                q.push(make_pair(dis[V[i]], V[i]));
            }
        }
    }
}

void dj2(int s, int n)
{
    priority_queue<pa, vector<pa>, greater<pa>> q2;
    for (int i = 1; i <= n; i++)
    {
        dis2[i] = inf;
        vis2[i] = 0;
    }
    dis2[s] = 0;
    q2.push(make_pair(0, s));
    while (!q2.empty())
    {
        int x = q2.top().second;
        q2.pop();
        if (vis2[x])
        {
            continue;
        }
        vis2[x] = 1;
        for (int i = point2[x]; i; i = nxt2[i])
        {
            if (dis2[V2[i]] > dis2[x] + W2[i])
            {
                dis2[V2[i]] = dis2[x] + W2[i];
                q2.push(make_pair(dis2[V2[i]], V2[i]));
            }
        }
    }
}

int main()
{
    int T;
    cin >> T;
    for (int ss = 1; ss <= T; ss++)
    {
        int sum = 0;
        int m, n;
        cin >> n >> m;
        int s, e, c;
        init();
        for (int i = 1; i <= m; i++)
        {
            cin >> s >> e >> c;
            add(s, e, c);
        }
        dj(1, n);
        // dj2(1, n);
        dj2(1, n);
        for (int i = 2; i <= n; i++)
        {
            sum = sum + dis[i] + dis2[i];
        }
        cout << sum << endl;
    }
   
    return 0;
}

E : 运输货物

问题描述

考虑一个具有 N 个顶点,M 条边的无向图。编号为 1 的顶点对应于一个矿山,从中提取一些珍贵的矿物。编号为 N 的顶点对应于一家矿物加工厂。每条边连接两个不同的顶点并拥有有两个参数,分别为最大承重量 C 和通行时间 D。现在将从矿山中提取的矿物并选择一条路径将提取的矿物运送至工厂。该路径应具有最大的承重量,以便能够同时运输尽可能多的矿物。路径的承重量等于路径中经过的边的最大承重量的最小值。但是,这些矿物非常敏感,一旦从矿山中提取出来,它们将在 T 时间单位后开始分解,除非他们在此时间间隔内到达工厂。因此,所选路径的总行进时间(其路径的通行时间之和)应小于或等于 T。

输入格式

输入的第一行包含一个整数 X,表示测试用例的数量。
每个测试用例的第一行包含 3 个整数,并用空格分隔:N,M,T。接下来的 M 行中的每行将包含四个整数,每个数字用空格分隔:A,B,C 和 D,这意味着顶点 A 和 B 之间存在一条边,最大承重量为 C,通行时间为 D。A 和 B 是 1 和 N 之间的不同整数。任何两个顶点之间最多存在一个边。

输出格式

对于 X 个测试用例,请输出在满足通行时间限制下的路径最大承重量,每个测试用例对应一行。
数据保证图中至少存在一条 1 到 n 通行总时间小于等于 T 的路径,即一定有解。

样例输入

2
2 1 10
1 2 13 10
4 4 20
1 2 1000 15
2 4 999 6
1 3 100 15
3 4 99 4

样例输出

13
99

数据规模和约定

1≤𝑛≤10000, 1≤m≤50000,1≤𝑇≤500000
1≤𝐶≤10000000, 1≤𝐷≤50000

解答

#include <bits/stdc++.h>
using namespace std;

#define MEM 100000
#define INF 10000000

// typedef long unsigned int;
typedef pair<int, int> par;

int dis[MEM], point[MEM], next1[MEM], wl[MEM], ct[MEM], v[MEM];
int mrkd[MEM];
int n, m;
int t, w;
int tot;

void init()
{
    tot = MEM - 1;
    while (1)
    {
        dis[tot] = INF;
        point[tot] = 0;
        next1[tot] = 0;
        wl[tot] = 0;
        ct[tot] = 0;
        v[tot] = 0;
        mrkd[tot] = 0;
        if (tot == 0)
            break;
        tot--;
    }
}

void add(int x, int y, int ww, int tt)
{
    tot++;                 // 获得新的内存地址(为新边节点申请内存)
    next1[tot] = point[x]; // 新边节点的下一个指向旧边节点
    point[x] = tot;        // 点x的指针更新指向新边节点
    v[tot] = y;            // 新边节点设置第二个连接点
    wl[tot] = ww;          // 为新边设置参数
    ct[tot] = tt;
}

void dijkstra(int s, int wwb)
{
    priority_queue<par, vector<par>, greater<par>> q;
    for (int i = 1; i <= n; i++)
    {
        dis[i] = INF;
        mrkd[i] = 0;
    }
    dis[s] = 0;
    q.push(make_pair(dis[s], s));
    while (!q.empty())
    {
        int x = q.top().second;
        q.pop();
        if (!mrkd[x])
        {
            mrkd[x] = 1;
            for (int p = point[x]; p; p = next1[p])
            {
                if (wl[p] >= wwb && dis[v[p]] > dis[x] + ct[p])
                {
                    dis[v[p]] = dis[x] + ct[p];
                    q.push(make_pair(dis[v[p]], v[p]));
                }
            }
        }
    }
}

bool inTime(int mw)
{
    dijkstra(1, mw);
    if (dis[n] > t)
    {
        return false;
    }
    return true;
}

int main()
{
    int att;

    cin >> att;
    for (int i = 1; i <= att; i++)
    {
        int ix, iy, iw, it;
        int leftw = 0, rightw = 3000000, mid;
        init();

        cin >> n >> m >> t;
        for (int i = 0; i < m; i++)
        {
            cin >> ix >> iy >> iw >> it;

            if (leftw > iw)
            {
                leftw = iw;
            }

            if (rightw < iw)
            {
                rightw = iw;
            }
            add(ix, iy, iw, it);
            add(iy, ix, iw, it);
        }

        mid = (leftw + rightw) / 2;
        while (mid != leftw && mid != rightw)
        {
            if (inTime(mid))
            {
                leftw = mid;
            }
            else
            {
                rightw = mid;
            }
            mid = (leftw + rightw) / 2;
        }
        if (inTime(rightw))
        {
            cout << rightw << endl;
        }
        else
        {
            cout << leftw << endl;
        }
    }
  
    return 0;
}

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值