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

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


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

border="0" width="330" height="86" src="//music.163.com/outchain/player?type=2&id=441473&auto=1&height=66">


题目背景

SOURCE:NOIP2015-HN-CJZX

题目描述

     H 教授是一位德高望重的教授,也是计算机科学界的权威。他对问题总有独特而深刻的见解,治学严谨,是学术界的带头人。
    在一次科学家大会上, H 教授在黑板上写下了 n 个式子 x1x2xn ,并向参加会议的所有科学家证明了:如果 x1=x2==xn ,那么可以证明 P=NP 。可是,毕竟人无完人,H 教授对其中的任意两个式子是否相等都说不清。他把这个问题抛给了全世界的科学家们。
    令人激动的是,没过多久, H 教授就收到了数学家们发来的 m email ,第 i email 写到,发信人已经证明了 lia<rixa=xa+1 xlix(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=x4 x6=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] 的前提是,前面有连边, 也顺带证明了, 前面的式子相等, 于是我们可以大摇大摆地连一条 i i1 的边, 并且是将所有的边都连起来, 因为只要你走到 i , 那么 i - 1 和 i 就是相等的, 不会矛盾,也不会有错连。 然后做一遍最短路。但是一定不要用 SPFA, 血的教训。

代码 :

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define LL long long
#define mp make_pair
using 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< pairint> > que;
    que.push(mp(0, 1));
    dis[1] = 0;
    while(!que.empty()) {
        pairint> 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<

本题结束

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

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

你可能感兴趣的:(NOIP模拟,图论,最短路)