题目描述
队爷为了造福社会,准备到各地去讲学。他的计划中有n个城市,从u到v可能有一条单向道路,通过这条道路所需费用为q。当队爷在u城市讲学完之后,u城市会派出一名使者与他同行,只要使者和他在一起,他到达某个城市就只需要花1的入城费且只需交一次,在路上的费用就可免去。。但是使者要回到u城市,所以使者只会陪他去能找到回u城市的路的城市。。队爷从1号城市开始讲学,若他在u号城市讲学完毕,使者会带他尽可能多的去别的城市。他希望你帮他找出一种方案,使他能讲学到的城市尽可能多,且费用尽可能小。
输入
第一行2个整数n,m。
接下来m行每行3个整数u,v,q,表示从u到v有一条长度为q的单向道路。
输出
一行,两个整数,为最大讲学城市数和最小费用。
样例输入
6 6
1 2 3
2 3 7
2 6 4
3 4 5
4 5 4
5 2 3
样例输出
6 10
提示
如上图,从1走到2,2城市使者会带他到3,4,5城市,回到2城市,再走到6,总费用为3+3+4=10。
对于20%的数据,1<=n<=20;
对于另外10%的数据,城市网络为一条单向链;
对于60%的数据,1<=m<=200000
对于100%的数据,1<=n<=100000
1<=m<=500000,1<=q<=1000, 保证无自环无重边。
思路
tarjan缩点后跑拓扑排序得解
代码实现
#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=500005;
const int M=500005;
const int INF=0x3f3f3f3f;
const ll LINF=1e18;
const ull sed=31;
const ll mod=998244353;
const double eps=1e-7;
const double PI=3.14159265358979;
typedef pair<int,int>P;
typedef pair<double,double>Pd;
struct node
{
int to,index,w;
}E[M];
int eu[M],ev[M],ew[M];
int n,m,cnt,head[N];
int Stack[N],dfn[N],low[N],tot,dep,top;
int ltp[N],ltps[N];
int deg[N],num[N],val[N];
bool viss[N];
queue<int>q;
void add(int u,int v,int w)
{
E[++cnt].to=v;
E[cnt].index=head[u];
E[cnt].w=w;
head[u]=cnt;
}
void tarjan(int u)
{
dfn[u]=low[u]=++dep;
Stack[++top]=u;
viss[u]=true;
for(int i=head[u];i;i=E[i].index)
{
if(!dfn[E[i].to])
{
tarjan(E[i].to);
low[u]=min(low[u],low[E[i].to]);
}
else if(viss[E[i].to]) low[u]=min(low[u],dfn[E[i].to]);
}
if(dfn[u]==low[u])
{
++tot;
int v;
do
{
v=Stack[top--];
viss[v]=false;
ltp[v]=tot;
++ltps[tot];
}while(u!=v);
}
}
void dfs(int u)
{
for(int i=head[u];i;i=E[i].index)
if(++deg[E[i].to]==1) dfs(E[i].to);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&eu[i],&ev[i],&ew[i]);
add(eu[i],ev[i],ew[i]);
}
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
memset(head,0,sizeof(head));
cnt=0;
for(int i=0;i<m;i++)
if(ltp[eu[i]]!=ltp[ev[i]])
add(ltp[eu[i]],ltp[ev[i]],ew[i]);
dfs(ltp[1]);
memset(val,0x3f,sizeof(val));
num[ltp[1]]=val[ltp[1]]=ltps[ltp[1]];
val[ltp[1]]--;
q.push(ltp[1]);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];i;i=E[i].index)
{
int v=E[i].to;
deg[v]--;
if(deg[v]==0) q.push(v);
if(num[v]<num[u]+ltps[v])
{
num[v]=num[u]+ltps[v];
val[v]=val[u]+E[i].w+ltps[v]-1;
}
else if(num[v]==num[u]+ltps[v])
val[v]=min(val[v],val[u]+E[i].w+ltps[v]-1);
}
}
int ans=0;
for(int i=1;i<=cnt;i++)
{
if(num[ans]<num[i]) ans=i;
else if(num[i]==num[ans] && val[i]<val[ans]) ans=i;
}
printf("%d %d\n",num[ans],val[ans]);
return 0;
}