P3119 [USACO15JAN]草鉴定
约翰有n块草场,编号1到n,这些草场由若干条单行道相连。奶牛贝西是美味牧草的鉴赏家,她想到达尽可能多的草场去品尝牧草。
贝西总是从1号草场出发,最后回到1号草场。她想经过尽可能多的草场,贝西在通一个草场只吃一次草,所以一个草场可以经过多次。
因为草场是单行道连接,这给贝西的品鉴工作带来了很大的不便,贝西想偷偷逆向行走一次,但最多只能有一次逆行。问,贝西最多能吃到多少个草场的牧草。
输入:
第一行:草场数n,道路数m。
以下m行,每行x和y表明有x到y的单向边,不会有重复的道路出现。
输出:
一个数,逆行一次最多可以走几个草场。
输入 #1
7 10 1 2 3 1 2 5 2 4 3 7 3 5 3 6 6 5 7 2 4 7
输出 #1
6
好久没有这么正式的将题面搬过来了;
显然需要tarjan求强连通分量;
但是我只会到这里,但是看题;
允许一条边反向,有点眼熟,啊,那个,就是那个
我们先缩点,dijkstra正向求最长路,再反向求最长路
枚举反向的边;
dis1[x]+dis2[v]-sum[belong[1]];
但是我们要保证能回去
#include<cstdio> #include<cstring> #include<queue> #include<stack> #include<algorithm> using namespace std; const int maxn=1e5+10; int n,m,pre[maxn],last[maxn],other[maxn],l; int pre0[maxn],last0[maxn],other0[maxn],l0; void add0(int x,int y) { l0++; pre0[l0]=last0[x]; last0[x]=l0; other0[l0]=y; } int dfn[maxn],low[maxn],cnt; void add(int x,int y) { l++; pre[l]=last[x]; last[x]=l; other[l]=y; } int pre2[maxn],last2[maxn],other2[maxn],l2; void add2(int x,int y) { l2++; pre2[l2]=last2[x]; last2[x]=l2; other2[l2]=y; } stack<int> s; int belong[maxn],qw; void dfs(int x) { dfn[x]=low[x]=++cnt; s.push(x); for(int p=last[x];p;p=pre[p]) { int v=other[p]; if(!dfn[v]) { dfs(v); low[x]=min(low[x],low[v]); } else if(!belong[v]) { low[x]=min(low[x],dfn[v]); } } if(dfn[x]==low[x]) { belong[x]=++qw; //printf("%d ",qw); while(1) { int y=s.top(); s.pop(); belong[y]=qw; if(x==y) break; } } } int sum[maxn]; int ans; int vis[maxn]; int dis1[maxn],dis2[maxn]; priority_queue<pair<int,int> >q; void dijkstra(int x) { memset(vis,0,sizeof(vis)); dis1[x]=sum[x]; q.push(make_pair(dis1[x],x)); while(!q.empty()) { int u=q.top().second; q.pop(); // printf("%d\n!",u); // printf("%d\n?",last[u]); // if(vis[u]) continue; // vis[u]=1; for(int p=last0[u];p;p=pre0[p]) { int v=other0[p]; //printf("!!"); if(dis1[v]<dis1[u]+sum[v]) { dis1[v]=dis1[u]+sum[v]; q.push(make_pair(dis1[v],v)); //printf("%d\n",dis1[v]); } } } } void dijkstra2(int x) { memset(vis,0,sizeof(vis)); dis2[x]=sum[x]; q.push(make_pair(dis2[x],x)); while(!q.empty()) { int u=q.top().second; q.pop(); // if(vis[u]) continue; // vis[u]=1; for(int p=last2[u];p;p=pre2[p]) { int v=other2[p]; if(dis2[v]<dis2[u]+sum[v]) { dis2[v]=dis2[u]+sum[v]; q.push(make_pair(dis2[v],v)); } } } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); add(x,y); } for(int i=1;i<=n;i++) { if(!dfn[i]) dfs(i); } //memset(pre,0,sizeof(pre)); for(int i=1;i<=n;i++) { sum[belong[i]]++; } //for(int i=1;i<=qw;i++) printf("%d ",sum[i]); for(int i=1;i<=n;i++) { for(int p=last[i];p;p=pre[p]) { int v=other[p]; if(belong[i]!=belong[v]) { add0(belong[i],belong[v]); add2(belong[v],belong[i]); } } } ans=sum[belong[1]]; dijkstra(belong[1]); dijkstra2(belong[1]); //for(int i =1;i<=n;i++) printf("%d ",dis1[i]); memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++) { if(vis[belong[i]]||!dis1[belong[i]]) continue; vis[belong[i]]=1; int x=belong[i]; for(int p=last2[x];p;p=pre2[p]) { int v=other2[p]; if(!dis2[v]) continue; ans=max(ans,dis1[x]+dis2[v]-sum[belong[1]]); } } printf("%d",ans); return 0; }