zoukankan      html  css  js  c++  java
  • [SDOI2009]晨跑

     原题连接:https://www.luogu.org/problemnew/show/P2153

    题目描述

    Elaxia最近迷恋上了空手道,他为自己设定了一套健身计划,比如俯卧撑、仰卧起坐等 等,不过到目前为止,他坚持下来的只有晨跑。 现在给出一张学校附近的地图,这张地图中包含N个十字路口和M条街道,Elaxia只能从 一个十字路口跑向另外一个十字路口,街道之间只在十字路口处相交。Elaxia每天从寝室出发 跑到学校,保证寝室编号为1,学校编号为N。 Elaxia的晨跑计划是按周期(包含若干天)进行的,由于他不喜欢走重复的路线,所以 在一个周期内,每天的晨跑路线都不会相交(在十字路口处),寝室和学校不算十字路 口。Elaxia耐力不太好,他希望在一个周期内跑的路程尽量短,但是又希望训练周期包含的天 数尽量长。 除了练空手道,Elaxia其他时间都花在了学习和找MM上面,所有他想请你帮忙为他设计 一套满足他要求的晨跑计划。

    存在1n 的边存在。这种情况下,这条边只能走一次。

    输入输出格式

    输入格式:

    第一行:两个数N,M。表示十字路口数和街道数。 接下来M行,每行3个数a,b,c,表示路口a和路口b之间有条长度为c的街道(单向)。

    输出格式:

    两个数,第一个数为最长周期的天数,第二个数为满足最长天数的条件下最短的路程长 度。

    输入输出样例

    输入样例

    7 10
    1 2 1
    1 3 1
    2 4 1
    3 4 1
    4 5 1
    4 6 1
    2 5 5
    3 6 6
    5 7 1
    6 7 1
    输出样例
    2 11

    说明

    对于30%的数据,N ≤ 20,M ≤ 120。

    对于100%的数据,N ≤ 200,M ≤ 20000。

     嗯....这道题目要求最短长度,最多天。那很显然跑最小费用最大流就可以了

    讲一讲建边qwq

    每个十字路口只能经过一次,既然这样,那我们就将每个十字路口拆成两个点 流量设为1,费用为0(为什么,想一想) a->a1(a1表示拆出来的点) qwq,但是源点,汇点不止走一次,所以不用拆点

    Code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int N=20000+10;
    const int M=6000000;
    const int inf=0x7fffffff;
    int v[N*4],w[N*4],cst[N*4],nxt[N*4],first[N],dis[N],pre[N],pos[N];  
    int cnt=1,n,m,flow,cost,t;
    bool inq[N];
    struct queue{
        int head,tail,que[M];
        void clear(){head=tail=1;}  //这一行其实没有意义
        void pop(){head++;if(head==M) head=0;}
        void push(int x){que[tail++]=x;if(tail==M) tail=0;}
        int front(){return que[head];}
        bool empty(){return head==tail;}
    };
    queue q;   //把queue封装在结构体里
    
    void read(int &x){   //读入优化
        x=0;int f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
        while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c-'0');c=getchar();}
        x*=f;
    }
    
    void add(int a,int b,int c,int d){  //前向星存边
        v[++cnt]=b;
        w[cnt]=c;
        cst[cnt]=d;
        nxt[cnt]=first[a];
        first[a]=cnt;
    }
    
    bool spfa(){     //找最小费用
        for(int i=1;i<=2*n;i++) dis[i]=inf;
        q.clear();
        q.push(1);dis[1]=0;inq[1]=1;
        while(!q.empty()){
            int x=q.front();q.pop();inq[x]=0;
            for(int i=first[x];i;i=nxt[i]){
                if(w[i]&&dis[x]+cst[i]<dis[v[i]]){
                    pre[v[i]]=x;pos[v[i]]=i;  //pre:记录前继节点,pos:该节点对应的边
                    dis[v[i]]=dis[x]+cst[i];
                    if(!inq[v[i]]){
                        q.push(v[i]);
                        inq[v[i]]=1;
                    }
                }
            }
        }
        return dis[n]!=inf;  //是否存在一条从源点到汇点的路径
    }
    
    int main(){
        read(n);read(m);
        for(int i=1;i<=m;i++){
            int a,b,c;
            read(a);read(b);read(c);
            if(a!=1) a=n+a;  //用拆出来的点连b,1不用拆点
            add(a,b,1,c);add(b,a,0,-c);
        }
        for(int i=2;i<n;i++){add(i,i+n,1,0);add(i+n,i,0,0);}  //拆点
        while(spfa()){
            int f=1;
            flow+=1;cost+=dis[n];
            for(int i=n;i!=1;i=pre[i]){
                w[pos[i]]-=f;
                w[pos[i]^1]+=f;
            }
        }
        printf("%d %d",flow,cost);
        return 0;
    }

     

  • 相关阅读:
    HCTF2018-admin
    SUCTF 2019-EasySQL
    BUUCTF-WEB-easy_tornado
    黑客攻防技术宝典web实战篇:攻击数据存储区习题
    可持久化数据结构·主席树(静态)
    Luogu P2661 [NOIP2015] 信息传递
    Luogu P2700 逐个击破
    Luogu P4779 【模板】单源最短路径(标准版)(Dijkstra+堆优化模板)
    Luogu P1962 斐波那契数列(矩阵乘法模板)
    Luogu P3366 【模板】最小生成树
  • 原文地址:https://www.cnblogs.com/lyf2/p/8445613.html
Copyright © 2011-2022 走看看