HNU2019暑期训练赛之2 B. Brexit Negotiations

Problem Description

As we all know, Brexit negotiations are on their way—but we still do not know whether they will actually finish in time.

The negotiations will take place topic-by-topic. To organise the negotiations in the most effective way, the topics will all be discussed and finalised in separate meetings, one meeting at a time.

This system exists partly because there are (non-cyclic) dependencies between some topics: for example, one cannot have a meaningful talk about tariffs before deciding upon the customs union. The EU can decide on any order in which to negotiate the topics, as long as the mentioned dependencies are respected and all topics are covered.

Each of the topics will be discussed at length using every available piece of data, including key results from past meetings. At the start of each meeting, the delegates will take one extra minute for each of the meetings that has already happened by that point, even unrelated ones, to recap the discussions and understand how their conclusions were reached. See Figure B.1 for an example.

Nobody likes long meetings. The EU would like you to help order the meetings in a way such that the longest meeting takes as little time as possible.


Figure B.1: Illustration of how time is spent in each meeting in a solution to Sample Input 2.

Input

The input consists of:
• One line containing an integer n(1≤n≤4⋅105)n (1 ≤ n ≤ 4 · 10^5)n(1n4105), the number of topics to be discussed. The topics are numbered from 1 to n.

• n lines, describing the negotiation topics.

The ith such line starts with two integers eie_iei and di(1≤ei≤106,0≤di&lt;n)d_i (1 ≤ e_i ≤ 10^6, 0 ≤ d_i &lt; n)di(1ei106,0di<n), the number of minutes needed to reach a conclusion on topic i and the number of other specific topics that must be dealt with before topic i can be discussed.

The remainder of the line has did_idi distinct integers bi,1,...,bi,di(1≤bi,j≤nb_i,1, . . . , b_i,d_i (1 ≤ b_i,j ≤ nbi,1,...,bi,di(1bi,jn and bi,j/=ib_i,j /= ibi,j/=i
for each j), the list of topics that need to be completed before topic i.

It is guaranteed that there are no cycles in the topic dependencies, and that the sum of di over all topics is at most 4⋅1054 · 10^54105.

Output

Output the minimum possible length of the longest of all meetings, if meetings are arranged optimally according to the above rules.

Sample Input

3
10 0
10 0
10 0

Sample Output

12

Sample Input2

6
2 2 4 3
4 1 5
1 2 2 4
3 1 5
2 0
4 1 3

Sample Output2

8


Problem

Given a DAG with vertex weights e(i), find a topological ordering π that minimizes max i (e(π(i)) +i).

Solution 1 more helpfully

• Basic idea: last vertex should have as small e(i) as possible.
• Adapt standard topological sort.
• Build schedule from end.
• Keep adding currently available topic with smallest e(i).
• Maintain available topics in priority queue.
• Time complexity O(nlogn+m).

Solution 2

• Ideally would like to sort vertices by decreasing value of e(i), but that might violate the precedence constraints.
• Assign potential p(i) = −e(i) for each vertex.
• Propagate potentials: for each predecessor j of i, must have p(j) ≤p(i)−1.
• Sorting by propagated potentials gives a valid and optimal ordering.



AC Code(C++)

#include <bits/stdc++.h>

using namespace std;
int const maxn = 4e5+5;
int n;
class Meeting
{
public:
    int time;
    int id;
    vector<int> pre;
    bool operator< (Meeting const& m2)const
    {
        return time>m2.time;
    }
};
vector<int> pre[maxn];
Meeting meetings[maxn];
Meeting tempMeetings[maxn];
void input(int id){
    meetings[id].id = id;
    cin >> meetings[id].time;
    int indeg;
    cin >> indeg;
    for(int i = 0; i < indeg; ++i){
        int foo;
        cin >> foo;
        meetings[id].pre.push_back(foo);
    }
}
int currMax;
int currStack[maxn];
bool visited[maxn];
int extraTime = 0;
int ans = 0;
void dfs(int currId){
    Meeting &currMeeting = tempMeetings[currId];
    if(!visited[currId]){
        int len = tempMeetings[currId].pre.size();
        for(int i = 0; i < len; ++i)
            dfs(currMeeting.pre[i]);
        visited[currId] = true;
        ans = max(ans, extraTime+currMeeting.time);
        ++extraTime;
        return;
    }else{
        return;
    }
}
/**
4
8 0
8 1 1
8 1 1
9 2 2 3
*/
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    for(int i = 1; i <= n; ++i){
        input(i);
        tempMeetings[i] = meetings[i];
    }
    sort(meetings+1,meetings+n+1);
    for(int i = 1; i <= n; ++i)
        dfs(meetings[i].id);
    cout << ans ;
    return 0;
}

ACM中确实不适合用Java
尤其是在递归深度较大的题目(默认情况下java的栈十分有限)

因为ACM判题还得看服务器的水平,服务器就是大哥,说你错就是错
java在OJ上跑容易出现各种各样的问题
例如这题。。
在这里插入图片描述
先放代码:


import java.io.*;
import java.util.*;

public class Main {
	//io 代码 已省略
    static class Meeting {
        int time;
        int id;
        ArrayList<Integer> pre = new ArrayList<>();

        Meeting(int time, int id) {
            this.time = time;
            this.id = id;
        }

        @Override
        public String toString() {
            return "Meeting{" +
                    "time=" + time +
                    ", id=" + id +
                    ", pre=" + pre +
                    '}';
        }
    }

    private static final int MAX_N = (int) 4e5 + 5;
    private static boolean[] visited = new boolean[MAX_N];
    private static int extraTime = 0;
    private static int ans = 0;
    private static Meeting[] meetings = new Meeting[MAX_N];
    private static Meeting[] tempMeetings = new Meeting[MAX_N];

    private static void input(int id) throws Exception {
        meetings[id] = new Meeting(nextInt(), id);
        int inDeg = nextInt();
        for (int i = 0; i < inDeg; ++i) {
            int foo = nextInt();
            meetings[id].pre.add(foo);
        }
    }

    private static void dfs(int currId) {
        Meeting currMeeting = tempMeetings[currId];
        if (!visited[currId]) {
            for (int pre : currMeeting.pre)
                dfs(pre);
            visited[currId] = true;
            ans = Math.max(ans, extraTime + currMeeting.time);
            ++extraTime;
        }
    }

    static int n;

    public static void main(String[] args) throws Exception {
        n = nextInt();
        for (int i = 1; i <= n; ++i) {
            input(i);
            tempMeetings[i] = meetings[i];
        }
        Arrays.sort(meetings, 1, n + 1, (o1, o2) -> Integer.compare(o2.time, o1.time));
        for (int i = 1; i <= n; ++i)
            dfs(meetings[i].id);
        System.out.println(ans);
    }
}

一度以为是StackOverflowError
因为栈有限,又无法加参数
于是我dfs部分改成手动栈模拟递归:


    private static void stackDfs(int start) {

        int i = 0;
        currId = start;
        do {
            Meeting currMeeting = tempMeetings[currId];
            if (visited[currId]) {
                if (returnStack.isEmpty())
                    break;
                StackData foo = returnStack.pop();
                // return;
                i = foo.preId;
                currId = foo.param;
            } else {
                if (i < currMeeting.pre.size()) {
                    returnStack.push(new StackData(i + 1, currId));

                    currId = currMeeting.pre.get(i); //give parameter
                    i = 0;  //new process. reset variable
                } else {
                    visited[currId] = true;
                    ans = Math.max(ans, extraTime + currMeeting.time);
                    ++extraTime;

                    if (returnStack.isEmpty())
                        break;
                    StackData foo = returnStack.pop();
                    // return;
                    i = foo.preId;
                    currId = foo.param;
                }
            }
        } while (true);
    }

依然RE, 改了一晚上,气得不行
一气之下, 将整个main函数都放在try的包围下,依然RE

  public static void main(String[] args) throws Exception {
        try {
            n = nextInt();
            for (int i = 1; i <= n; ++i) {
                input(i);
                tempMeetings[i] = meetings[i];
            }
            Arrays.sort(meetings, 1, n + 1, (o1, o2) -> Integer.compare(o2.time, o1.time));
        } catch (Throwable ignored) {

        }
        for (int i = 1; i <= n; ++i) {
            try {
                dfs(meetings[i].id);
            } catch (Throwable ignored) {

            }
        }

        System.out.println(ans);
    }

代码已经被try包的死死的,还RE就一定不是抛异常的问题了。。。这根本就是服务器的问题!!!!!!!!!!!!!!!!!!!

队友搞到了题目的数据
进行测试:


    public static void main(String[] args) throws Exception {
        int correctNum = 0;
        int total = 0;
        File dir = new File("testData/");
        File[] files = dir.listFiles();
        for (File file : files) {
            if (!file.getName().contains(".in"))
                continue;
            File ansFile = new File("testData/" + file.getName().replace(".in", ".ans"));

            long start = System.currentTimeMillis();

            setStream(new FileInputStream(file));
            ++total;
            n = nextInt();
            for (int i = 1; i <= n; ++i) {
                input(i);
                tempMeetings[i] = meetings[i];
            }
            Arrays.sort(meetings, 1, n + 1, (o1, o2) -> Integer.compare(o2.time, o1.time));

            for (int i = 1; i <= n; ++i) {
                dfs(meetings[i].id);
            }
            long end = System.currentTimeMillis();
//            System.out.println(ans);
            setStream(new FileInputStream(ansFile));
            int std = nextInt();
            if (ans == std) {
                ++correctNum;
                System.out.println("Correct " + file.getName() + "  Time: " + (end - start) + "ms");
            } else {
                System.err.println("Error: " + file.getName());
                System.err.println("Expected: " + std + "  Yours: " + ans);
                break;
            }

            Arrays.fill(visited, false);
            extraTime = 0;
            ans = -1;
        }
        System.out.println("Correct num: " + correctNum + "  total: " + total);
    }

结果:

Correct 01-sink.in Time: 26ms
Correct 02-chains.in Time: 0ms
Correct 03-source.in Time: 0ms
Correct 04-bottleneck.in Time: 0ms
Correct 05-scatter-gather.in Time: 1ms
Correct 06-chain-detour.in Time: 1ms
Correct 07-bipartite.in Time: 1ms
Correct 08-lattice.in Time: 1ms
Correct 20-minimal.in Time: 0ms
Correct 21-small_random.in Time: 0ms
Correct 22-small_random.in Time: 0ms
Correct 23-small_random.in Time: 1ms
Correct 24-small_random.in Time: 1ms
Correct 25-small_random.in Time: 0ms
Correct 26-small_random.in Time: 16ms
Correct 27-small_random.in Time: 0ms
Correct 28-small_random.in Time: 0ms
Correct 29-small_random.in Time: 0ms
Correct 30-small_random.in Time: 1ms
Correct 31.in Time: 1ms
Correct 32.in Time: 6ms
Correct 33.in Time: 207ms
Correct 34-norelations.in Time: 5ms
Correct 35-twochains.in Time: 61ms
Correct 36-cube_random_weights.in Time: 8ms
Correct 37-cube_subset_random_weights.in Time: 3ms
Correct 38-identicalWeights.in Time: 66ms
Correct 39-halfchain-halfopen.in Time: 4ms
Correct 40-complete.in Time: 186ms
Correct 41-empty.in Time: 1649ms
Correct 42-two_paths_same_source.in Time: 1964ms
Correct 43-two_paths_same_sink.in Time: 1445ms
Correct 44-two_paths_same_ends.in Time: 1039ms
Correct 45-bipartite.in Time: 944ms
Correct 46-star_maxanswer.in Time: 590ms
Correct 47-half_star_uniform_costs.in Time: 881ms
Correct 48-half_star_decreasing_costs.in Time: 891ms
Correct 49-star_decreasing_costs.in Time: 932ms
Correct 50-star_uniform_costs.in Time: 1096ms
Correct 51-max_random.in Time: 974ms
Correct 52-max_divisibility_lattice.in Time: 1054ms
Correct 53-max_decreasing_costs.in Time: 1027ms
Correct 54-chain_almost_constant_costs.in Time: 958ms
Correct 55-random.in Time: 701ms
Correct 56-random.in Time: 100ms
Correct 57-random.in Time: 447ms
Correct 58-random.in Time: 105ms
Correct 59-random.in Time: 338ms
Correct 60-random.in Time: 131ms
Correct 61-random.in Time: 781ms
Correct 62-random.in Time: 716ms
Correct 63-random.in Time: 450ms
Correct 64-random.in Time: 688ms
Correct num: 53 total: 53

完全正确!

(至于文件到64,为什么total是53, 因为样例的编号是不连续的。。。。。)
在这里插入图片描述
无法理解RE是怎么来的(这也印证了ACM中不到迫不得已不用其他语言 即使代码是对的,也容易被客观因素冤枉)

顺便测试了模拟递归的函数,也都通过了 ^ ^ 没有写错

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值