[NOIP模拟] 证明 proof

来源:互联网 发布:pps网络电视播放器apk 编辑:程序博客网 时间:2024/05/22 20:12

[NOIP模拟] 证明 proof - 最短路


阅读本文推荐BGM: The end of the world - 岸部眞明


题目背景

SOURCE:NOIP2015-HN-CJZX

题目描述

    H 教授是一位德高望重的教授,也是计算机科学界的权威。他对问题总有独特而深刻的见解,治学严谨,是学术界的带头人。
    在一次科学家大会上,H 教授在黑板上写下了 n 个式子 x1x2xn ,并向参加会议的所有科学家证明了:如果 x1=x2==xn,那么可以证明 P=NP。可是,毕竟人无完人,H 教授对其中的任意两个式子是否相等都说不清。他把这个问题抛给了全世界的科学家们。
    令人激动的是,没过多久,H 教授就收到了数学家们发来的 memail ,第 iemail 写到,发信人已经证明了 lia<rixa=xa+1xlix(li)+1xri 两两相等。但是,这些证明是有版权的,如果 H 教授需要使用这些证明,那么需要向提供证明的人支付 ci 元稿费。

    H 教授希望通过这些信息证明出 P=NP。但是,H 教授最近手头拮据,所以希望支付最小的费用。

输入格式

输入的第一行是两个整数 nm
接下来 m 行,每行三个整数 lirici(1lirin),代表第 i 位数学家的证明及其稿费。

输出格式

输出只包含一个整数,表示 H 教授至少要支付多少元稿费,才能证明出 P=NP。如果根据现有条件无法证明 P=NP ,请输出 1

样例数据 1

Input 

9 3
1 3 101010
4 6 98889
7 9 76543
Outout

-1

样例数据 2

Input 

9 7
1 5 3
3 6 8
5 8 4
4 7 6
2 3 7
7 9 2
6 7 5
Output

9

备注

【样例1说明】
就算把所有的数学家都叫上,仍然证明不了 x3=x4x6=x7

【样例2说明】
第一位数学家可以证明 x1=x2=x3=x4=x5
第三位数学家可以证明 x5=x6=x7=x8
第六位数学家可以证明 x7=x8=x9
这三位数学家是足够的,并且只需 9 元稿费。可以证明没有更优的方案。

【数据说明】
所有测试点的数据范围如下表所示。
数据说明

谈谈想法 :

    首先表示对那些卡 SPFA 的人说一声 : “谢谢(233)”, 我今天用 SPFA 被卡了 40 分, 气炸。

正题 :

    这道题是一道比较裸的最短路, 只是比较优秀的建边还是要想一想的。
     dis[i] 表示证明 1 到 i 式子所需的最小代价, 先按照数据所给的建边, 对于相等式子 xi,xi+1.......xj 连一条 i 到 j 的长度为 a[i] 的边, 我们会发现, 当证明了 i 到 j 相等, 则 i 到 j 里的所有的式子相等可以有连边,于是不妨想想整个情况, 对于dis[i], 我们扫到 dis[i] 的前提是,前面有连边, 也顺带证明了, 前面的式子相等, 于是我们可以大摇大摆地连一条 ii1 的边, 并且是将所有的边都连起来, 因为只要你走到 i , 那么 i - 1 和 i 就是相等的, 不会矛盾,也不会有错连。 然后做一遍最短路。但是一定不要用 SPFA, 血的教训。

代码 :

#include <cstdio>#include <cstdlib>#include <cstring>#include <string>#include <algorithm>#include <iostream>#include <cmath>#include <ctime>#include <map>#include <vector>#include <queue>#define LL long long#define mp make_pairusing namespace std;inline int read() {    int i = 0, f = 1;    char ch = getchar();    while(ch < '0' || ch > '9') {        if(ch == '-') f = -1; ch = getchar();    }    while(ch >= '0' && ch <= '9') {        i = (i << 3) + (i << 1) + ch - '0'; ch = getchar();    }    return i * f;}inline LL readL() {    LL i = 0, f = 1;    char ch = getchar();    while(ch < '0' || ch > '9') {        if(ch == '-') f = -1; ch = getchar();    }    while(ch >= '0' && ch <= '9') {        i = (i << 3) + (i << 1) + (LL)(ch - '0'); ch = getchar();    }    return i * f;}const int MAXN = 6e5 + 10;int first[MAXN], to[MAXN * 2], nxt[MAXN * 2], n, m, a[MAXN * 2];int k, tot;LL len[MAXN * 2], dis[MAXN * 2];bool used[MAXN * 2];struct point {    int from, to; LL v;};point e[MAXN * 2];queue<int> q;inline void addedge(int x, int y, LL z) {    nxt[++tot] = first[x]; first[x] = tot; to[tot] = y, len[tot] = z;}inline void work(int l) {    sort(a + 1, a + l + 1);    k = unique(a + 1, a + l + 1) - a - 1;    for(int i = 1; i <= m; ++i) {        e[i].from = lower_bound(a + 1, a + k + 1, e[i].from) - a;        e[i].to = lower_bound(a + 1, a + k + 1, e[i].to) - a;    }}inline LL dij() {    for(int i = 1; i <= n; ++i) dis[i] = 1e17;    priority_queue< pair<LL, int> > que;    que.push(mp(0, 1));    dis[1] = 0;    while(!que.empty()) {        pair<LL, int> s = que.top();        que.pop();        used[s.second] = true;        for(int u = first[s.second]; u; u = nxt[u]) {            if((LL)(dis[s.second] + len[u]) < dis[to[u]])                dis[to[u]] = dis[s.second] + len[u], que.push(mp(-dis[to[u]], to[u]));        }    }    return dis[n];}int main() {    n = read(), m = read();    for(int i = 1; i <= m; ++i) e[i].from = read(), e[i].to = read(), e[i].v = readL();    int l = 0;    for(int i = 1; i <= m; ++i) a[++l] = e[i].from, a[++l] = e[i].to; a[++l] = n; a[++l] = 1;    work(l);    for(int i = 1; i <= m; ++i) {        addedge(e[i].from, e[i].to, e[i].v);    }    for(int i = 2; i <= k; ++i)        addedge(i, i - 1, 0);    cout<<dij();}

本题结束

感谢阅读本篇文章,喜欢的话,点个赞吧,你的鼓励就是我最大的动力

有什么意见,尽情发表吧。

原创粉丝点击