P3119 [USACO15JAN]Grass Cownoisseur G
阿新 • • 發佈:2020-07-31
P3119 [USACO15JAN]Grass Cownoisseur G
和大佬同桌一起做的,感謝大佬對我的指導,貼一下Ta的部落格
我的最開始的思路就是DFS,因為想著DFS可以列舉往回走的情況,然而我發現題目讀錯了。逆行相當於建一條反向邊,但是並沒有規定必須在走過的路中逆行,你可以提前建這樣一條反向邊
然而我以為只能在走過的路中逆行,完美爆0
過了很久之後把Tarjan的很多題都刷了,然後找到了這道題,發現我們完全通過縮點把一些環縮成一個點,然後繼續處理
如果沒有這個逆行,我會想著跑最長路(SPFA或者拓撲排序),但是對於這個逆行,即建一條反向邊,應該如何處理呢
沒錯,分層圖。我記得我在我的部落格中單獨寫了一篇文章講分層圖,但是放在那裡面的題比較入門,建議先學一學。因為只需要建一條反向邊,所以我們就只需要兩層圖就夠了
記住,在分層圖中,我們新建的一層圖是不會改變原圖的結構的,後面的每一層圖想較於第一層圖(原圖)來說,是一模一樣的建邊,但是對於這個逆行,對於當前節點 \(i\),到達節點 \(j\) ,應該建一條 \(j\) 到 \(i+cnt\) 的邊,然後跑最長路,整個題就解決了
#include <bits/stdc++.h> using namespace std; int n,m,x[520010],y[520010],ti,tot,cnt,ans,top,q[520010]; int dfn[520010],low[520010],dis[520010],vis[520010],num[520010],fir[520010],head[520010]; struct node { int to,net,val; } e[5200010]; inline void add(int u,int v,int w) { e[++tot].to=v; e[tot].val=w; e[tot].net=head[u]; head[u]=tot; } inline void tarjan(int x) { dfn[x]=low[x]=++ti; q[++top]=x; vis[x]=1; for(register int i=head[x];i;i=e[i].net) { int v=e[i].to; if(!dfn[v]) { tarjan(v); low[x]=min(low[x],low[v]); } else { if(vis[v]) low[x]=min(low[x],dfn[v]); } } if(dfn[x]==low[x]) { ++cnt; while(q[top+1]!=x) { fir[q[top]]=cnt; num[cnt]++; vis[q[top]]=0; top--; } } } inline void spfa(int s) { for(register int i=1;i<=520000;i++) { vis[i]=0; dis[i]=-1; } queue<int> q; vis[s]=1; dis[s]=0; q.push(s); while(!q.empty()) { int x=q.front(); q.pop(); vis[x]=0; for(register int i=head[x];i;i=e[i].net) { int v=e[i].to; if(dis[v]<dis[x]+e[i].val) { dis[v]=dis[x]+e[i].val; if(!vis[v]) { vis[v]=1; q.push(v); } } } } } int main() { scanf("%d%d",&n,&m); for(register int i=1;i<=m;i++) { scanf("%d%d",&x[i],&y[i]); add(x[i],y[i],0); } for(register int i=1;i<=n;i++) { if(!dfn[i]) tarjan(i); } tot=0; memset(head,0,sizeof(head)); for(register int i=1;i<=m;i++) { if(fir[x[i]]==fir[y[i]]) continue; add(fir[x[i]],fir[y[i]],num[fir[x[i]]]); add(fir[x[i]]+cnt,fir[y[i]]+cnt,num[fir[x[i]]]); add(fir[y[i]],fir[x[i]]+cnt,num[fir[y[i]]]); //注意分層圖的建邊,這題只需要兩層圖 } spfa(fir[1]); //在縮完點之後的圖中跑最長路 printf("%d",dis[fir[1]+cnt]); //第二層圖用來往回走 return 0; }