[USACO15JAN]草鑒定Grass Cownoisseur
阿新 • • 發佈:2018-09-22
usaco 部分 %d using pop pty memset tarjan ems
tarjan縮點+最短路
這道題我想了一半的正解,就是縮點+DAG上考慮,之後圖只有一種情況:1號點連著大量的點,大量的點連著1號點,部分能到達1號點的點連接著1號點能到達的部分點。轉向就是要從1號點能到達的點過渡到能到達1號點的點。考慮spfa,在縮完點後的圖上從1號點正向跑最大路,再建立一個反圖,跑最大路。這樣我們枚舉每一個點(縮後的點),找到他連接的點,如果合法,那麽ans=max(ans,-1*val[firs]+diss[i]+disf[v]);
code:
#include<cstdio> #include<cstring> #include<iostream> #include<queue> #include<cstring> #include<vector> #include<stack> using namespace std; const int maxn=500006; int x1,x2,y1,y2; struct hzw { int to,next,u; }e[maxn],ed1[maxn],ed2[maxn]; int head[maxn],head1[maxn],head2[maxn],cur,n,m,k; inline void add(int a,int b,hzw e[],int head[]) { e[cur].u=a; e[cur].to=b; e[cur].next=head[a]; head[a]=cur++; } stack<int>ss; bool pan[maxn]; int cnt,col,val[maxn],firs,low[maxn],dfn[maxn],bel[maxn],disf[maxn],diss[maxn]; inline void tarjan(int s) { low[s]=++cnt; dfn[s]=cnt; ss.push(s); for (int i=head[s];i!=-1;i=e[i].next) { int v=e[i].to; if (!dfn[v]) { tarjan(e[i].to); low[s]=min(low[s],low[v]); } else if (!pan[v]) { low[s]=min(low[s],dfn[v]); } } if (low[s]==dfn[s]) { col++; while (ss.top()!=s) { int fr=ss.top(); ss.pop(); pan[fr]=1; bel[fr]=col; val[col]++; if (fr==1) firs=col; } int fr=ss.top(); ss.pop(); pan[fr]=1; bel[fr]=col; val[col]++; if (fr==1) firs=col; } } bool vis[maxn]; void spfa(int s,hzw e[],int dis[],int *head){ memset (vis,0,sizeof (vis)); memset(dis,-1,sizeof(dis)); queue<int>q; q.push(s); dis[s]=val[firs]; vis[s]=true; while (!q.empty()){ int u=q.front(); q.pop(); vis[u]=false; for (int i=head[u];i!=-1;i=e[i].next){ int a=e[i].to; if (dis[a]<dis[u]+val[a]){ dis[a]=dis[u]+val[a]; if (!(vis[a])){ q.push(a); vis[a]=true; } } } } } int main() { memset(head,-1,sizeof(head)); memset(head1,-1,sizeof(head1)); memset(head2,-1,sizeof(head2)); cin>>n>>m; for (int i=1,a,b;i<=m;++i) { scanf("%d%d",&a,&b); add(a,b,e,head); } for (int i=1;i<=n;++i) if (!dfn[i]) {tarjan(i);} for (int i=0;i<m;++i) { int x=bel[e[i].u],y=bel[e[i].to]; if (x!=y) { add(x,y,ed1,head1); add(y,x,ed2,head2); } } spfa(firs,ed1,disf,head1); spfa(firs,ed2,diss,head2); int ans=val[firs]; for (int i=1;i<=col;++i) { if (!diss[i]) continue; for (int j=head1[i];j!=-1;j=ed1[j].next) { int v=ed1[j].to; if (!disf[v]) continue; ans=max(ans,-1*val[firs]+diss[i]+disf[v]); } } cout<<ans; return 0; }
收獲:
註意最長,最短路有時能解決常見的dp問題(有起點的那種),並且能夠判斷狀態是否合法。
[USACO15JAN]草鑒定Grass Cownoisseur