zoukankan      html  css  js  c++  java
  • NOIP模拟赛 队爷的讲学计划

    队爷的讲学计划

    问题描述

    队爷为了造福社会,准备到各地去讲学。他的计划中有n 个城市,从 u 到 v 可能有一条单向道路,通过这条道路所需费用为 q。当队爷在 u 城市讲学完之后,u 城市会派出一名使者与他同行,只要使者和他在一起,他到达某个城市就只需要花 1 的入城费且只需交一次,在路上的费用就可免去。。但是使者要回到 u 城市,所以使者只会陪他去能找到回 u 城市的路的城市。。队爷从 1 号城市开始讲学,若他在u 号城市讲学完毕,使者会带他尽可能多的去别的城市。
    他希望你帮他找出一种方案,使他能讲学到的城市尽可能多,且费用尽可能小。

    输入文件

    第一行 2 个整数 n,m。
    接下来 m 行每行 3 个整数 u,v,q,表示从 u 到 v 有一条长度为 q的单向道路。

    输出文件

    一行,两个整数,为最大讲学城市数和最小费用。

    数据规模与约定

    对于 20%的数据,1<=n<=20;
    对于另外 10%的数据,城市网络为一条单向链;
    对于 60%的数据,1<=m<=200000
    对于 100%的数据,1<=n<=100000
    1<=m<=500000,1<=q<=1000, 保证无自环无重边。

    分析

    对于那些可以回到自己的点一定在一个强连通分量中,所以先用tarjan算法缩点重新建边之后得到一个DAG(有向无环图),可以用拓扑排序,也可以用spfa,这题数据不卡spfa。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int N=100010;
    const int M=500010;
    inline int read(){
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int n,m,tot,idx,top,cnt,ans;
    int head[N],dis[N],u[M],v[M],w[M],f[N],g[N];
    int dfn[N],low[N],sta[N],B[N],du[N],s[N];
    bool instack[N];
    queue<int>q;
    struct node{
        int next,to,dist;
    }e[M];
    inline void ins(int from,int to,int dist){
        e[++tot].next=head[from];
        e[tot].to=to; e[tot].dist=dist;
        head[from]=tot;
    }
    void tarjan(int x){
        dfn[x]=low[x]=++idx;
        sta[++top]=x; instack[x]=true;
        for(int i=head[x];i;i=e[i].next)
        if(!dfn[e[i].to]){
            tarjan(e[i].to);
            low[x]=min(low[x],low[e[i].to]);
        }else if(instack[e[i].to])
            low[x]=min(low[x],dfn[e[i].to]);
        if(dfn[x]==low[x]){
            ++cnt; int y;
            do{
                y=sta[top--];
                instack[y]=false;
                B[y]=cnt; ++s[cnt];
            }while(x!=y);
        }
    }
    void dfs(int x){
        for(int i=head[x];i;i=e[i].next)
        if(++du[e[i].to]==1) dfs(e[i].to);
    }
    int main(){
        freopen("teach.in","r",stdin);
        freopen("teach.out","w",stdout);
        n=read();m=read();
        for(int i=1;i<=m;++i){
            u[i]=read();v[i]=read();w[i]=read();
            ins(u[i],v[i],w[i]);
        }
        for(int i=1;i<=n;++i)
        if(!dfn[i]) tarjan(i);
        tot=0;memset(head,0,sizeof(head));
        for(int i=1;i<=m;++i)
        if(B[u[i]]!=B[v[i]])
        ins(B[u[i]],B[v[i]],w[i]);
        memset(g,0x3f,sizeof(0x3f));
        f[B[1]]=g[B[1]]=s[B[1]]; --g[B[1]];
        dfs(B[1]); q.push(B[1]);
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=head[x];i;i=e[i].next){
                int to=e[i].to; --du[to];
                if(!du[to]) q.push(to);
                if(f[x]+s[to]>f[to]){
                    f[to]=f[x]+s[to]; g[to]=g[x]+e[i].dist+s[to]-1;
                }else if(f[x]+s[to]==f[to])
                    g[to]=min(g[to],g[x]+e[i].dist+s[to]-1);
            }
        }
        for(int i=1;i<=cnt;++i)
        if(f[i]>f[ans]) ans=i;
        else if(f[i]==f[ans]&&g[i]<g[ans]) ans=i;
        printf("%d %d
    ",f[ans],g[ans]);
        return 0;
    }
  • 相关阅读:
    夺命雷公狗---node.js---21之项目的构建在node+express+mongo的博客项目6之数据的遍历
    夺命雷公狗---node.js---20之项目的构建在node+express+mongo的博客项目5mongodb在项目中实现添加数据
    夺命雷公狗---node.js---19之项目的构建在node+express+mongo的博客项目4mongodb在项目中的基本引入
    夺命雷公狗---node.js---18之项目的构建在node+express+mongo的博客项目3头尾左侧分离法
    夺命雷公狗---node.js---17之项目的构建在node+express+mongo的博客项目2之一,二级路由
    夺命雷公狗---node.js---16之项目的构建在node+express+mongo的博客项目1
    夺命雷公狗---node.js---15之加密
    夺命雷公狗---node.js---14之DNS
    夺命雷公狗---node.js---13之Buffer的转换
    夺命雷公狗---node.js---12之fs模块文件的操作
  • 原文地址:https://www.cnblogs.com/huihao/p/7786461.html
Copyright © 2011-2022 走看看