zoukankan      html  css  js  c++  java
  • 题解——洛谷P1250 种树(差分约束)

    一道看一眼就知道差分约束的题目

    但是最短路spfa的时候注意松弛条件是

    if(dis[u]+w[i]<dis[v[i]])
        dis[v[i]]=dis[u]+w[i];

    不能写成

    if(dis[u]+w[i]<=dis[v[i]])
        dis[v[i]]=dis[u]+w[i]

    否则会TLE


    就是如何把( a_{i}-a_{j} ge t ),方法非常简单,只需要乘上-1 就可以愉快地变成( a_{j}-a_{i} le -t )了

    然后就是建立图。

    瞪眼法可知我们可以使用类似前缀和的结构来维护一个到第i个位置一共种了多少颗树的信息

    然后我们设( d_{i} ) 表示到第i个位置现在有多少颗树

    题目中要求的条件

    BE中间种的树的数量不少于T

    就可以转化为 ( d_{e}-d_{b-1} ge t )了,然后用到刚才的转化方法

    把式子化成 ( d_{b-1}-d_{e} le -t )了

    所以我们可以从e向b-1连一条边权为-t的边

    建完了这些边之后,我们会发现一个问题,这个图没办法直接跑最短路解出解废话因为这个图根本不联通啊

    所以我们要来思考一下还有什么其他的约束条件

    首先显而易见的有

    ( d_{n+1}-d_{i} le 0 ,0 le i ge n ) 即 ( d_{i}-d_{n+1} ge 0 ,0 le i le n ) ,所以我们可以从n+1的节点连一条边权为0的边到第i个节点

    其次还有几个显而易见的结论

    (d_{i}-d_{i-1} ge 1 )

    (d_{i-1} - d_{i} ge 0)

    同样的从i-1向i连一条边权为1的边,再从i向i-1连一条边权为0的边

    大功告成!

    然后我们想想好像也没啥其他条件了

    跑一边spfa最短路

    然后差分做出来的是相对的大小qwq

    所以如果最后的dis[n]能减去一个mindis的话,解会更优且不会违背条件

    然后贴代码

    #include <cstdio>
    #include <algorithm>
    #include <queue>
    #include <cstring>
    using namespace std;
    const int MAXN = 30101;
    const int MAXM = 100101;
    int cnt=0,u[MAXM],v[MAXM],w[MAXM],first[MAXN],next[MAXM];
    bool vis[MAXN];
    int inq[MAXN],dis[MAXN];
    int n,h;
    void addedge(int ux,int vx,int wx){
        ++cnt;
        u[cnt]=ux;
        v[cnt]=vx;
        w[cnt]=wx;
        next[cnt]=first[ux];
        first[ux]=cnt;
    }
    int spfa(int s,int t){
        queue<int> q;
        for(int i=0;i<=n+1;i++){
            dis[i]=0x3f3f3f3f;
            }
        q.push(s);
        dis[s]=0;
        inq[s]=1;
        vis[s]=1;
        while(!q.empty()){
            int u=q.front();
            q.pop();
            vis[u]=0;
            for(int i=first[u];i;i=next[i]){
                if(w[i]+dis[u]<dis[v[i]]){
                    dis[v[i]]=w[i]+dis[u];
                    if(!vis[v[i]]){
                        vis[v[i]]=1;
                        inq[v[i]]++;
                        q.push(v[i]);
                        if(inq[v[i]]>n)
                            return 0x3f3f3f3f;
                    }
                }
            }
        }
    }
    int main(){
        scanf("%d %d",&n,&h);
        int b,e,t;
        for(int i=1;i<=h;i++){
            scanf("%d %d %d",&b,&e,&t);
            addedge(e,b-1,-t);
        }
        addedge(n+1,0,0);
        for(int i=1;i<=n;i++){
            addedge(n+1,i,0);
            addedge(i,i-1,0);
            addedge(i-1,i,1);
        }
        spfa(n+1,0);
        int mind=0x3f3f3f3f;
        for(int i=0;i<=n;i++){
            mind=min(mind,dis[i]);    
        }
        printf("%d",dis[n]-mind);
        return 0;
    }
  • 相关阅读:
    字体最小值
    javascript常用事件
    豆瓣移动端风格的css命名方法与学习
    JS基础函数
    css3动画
    html与css的移动端与pc端需要注意的事项
    javascript什么是函数
    JavaScript基础学习
    开始学javascript基础
    使用css3属性,大部分浏览器要识别前缀
  • 原文地址:https://www.cnblogs.com/dreagonm/p/9427259.html
Copyright © 2011-2022 走看看