1. 程式人生 > >草鑒定

草鑒定

front ring == target span ... names space main

這個題調了一天。。

傳送門

讀完題目之後我們不難想出這個題是個tarjan縮點問題,因為盡量多的經過草場,所以一號點所在的強連通分量裏左右的點都是不需要在進行走逆向邊,所能到達的。

然後問題就落在怎麽處理我們走這一次逆向邊上。

仔細看題目要求,題目要求我們必須從一號點出發,最後回到一號點。所以我想到了建一個逆向的圖,虛擬出cnt + 1 , cnt+2,cnt+3.....n+cnt號點,建一個逆向圖(用進行縮點之後的點集重新構造),因為我們求出進過草場最多是多少,所以我們將強連通分量中有多少個點在縮點中記錄下來(num[i]:表示第ii個強連通分量中有多少個點),將它作為邊權。

最後我們只要從1號點所在的強連通分量開始,跑一邊最長路就好了,最後輸出從1號點到我們虛擬出來的1 + cnt號點就好了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn = 2e5 + 5;

inline int read(){
    char ch = getchar();
    int f = 1 , x = 0;
    while(ch > 9 || ch < 0){if(ch == -)f = -1;ch = getchar();}
    
while(ch >= 0 && ch <= 9){x = (x << 1) + (x << 3) + ch - 0;ch = getchar();} return x * f; } int n,m,x,y; int head[maxn],tot,head2[maxn],tot2; int ans; struct Edge{ int from,to,next; }edge[maxn << 1],edge2[maxn << 1]; void add(int u,int v){ edge[
++tot].from = u; edge[tot].to = v; edge[tot].next = head[u]; head[u] = tot; } void add_edge(int u,int v){ edge2[++tot2].from = u; edge2[tot2].to = v; edge2[tot2].next = head2[u]; head2[u] = tot2; } int dfn[maxn],low[maxn],ind; int belong[maxn],num[maxn],cnt,stack[maxn],top; bool ins[maxn]; void tarjan(int x){ low[x] = dfn[x] = ++ind; ins[x] = true; stack[++top] = x; for(int i=head[x];i;i=edge[i].next){ int v = edge[i].to; if(ins[v]) low[x] = min(low[x] , dfn[v]); if(!dfn[v]) { tarjan(v); low[x] = min(low[x] , low[v]); } } int k = 0; if(dfn[x] == low[x]){ cnt++; do{ k = stack[top]; num[cnt]++; top--; ins[k] = false; belong[k] = cnt; } while(k != x); } } int dis[maxn]; bool vis[maxn]; void spfa(int s){ queue<int> q; q.push(s); dis[s] = 0; vis[s] = true; while(!q.empty()){ int cur = q.front(); q.pop(); vis[cur] = false; for(int i=head2[cur];i;i=edge2[i].next){ int v = edge2[i].to; if(dis[v] < dis[cur] + num[cur]){ dis[v] = dis[cur] + num[cur]; if(vis[v] == 0){ q.push(v); vis[v] = true; } } } } } int main(){ n = read(); m = read(); for(int i=1;i<=m;i++){ x = read(); y =read(); add(x , y); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); for(int i=1;i<=n;i++) num[i + cnt] = num[i]; for(int i=1;i<=m;i++) if(belong[edge[i].from] != belong[edge[i].to]){ add_edge(belong[edge[i].from] , belong[edge[i].to]); add_edge(belong[edge[i].to] , belong[edge[i].from] + cnt); add_edge(belong[edge[i].from] + cnt , belong[edge[i].to] + cnt); } spfa(belong[1]); printf("%d\n",dis[belong[1] + cnt]); return 0; }

草鑒定