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\n",f[ans],g[ans]);
    return 0;
}

 

posted @ 2017-11-05 08:04  沐灵_hh  阅读(284)  评论(0编辑  收藏  举报