1. 程式人生 > 實用技巧 >4269. 【NOIP2015模擬10.27】挑竹籤

4269. 【NOIP2015模擬10.27】挑竹籤

洛谷AC傳送門

題目讓我們求最多可以抽走多少個竹籤。官方題解是建圖然後求拓補排序。 蒟蒻表示根本不用這樣。

首先,同樣的,我們從上面的竹籤向被壓竹籤建有向圖。可以發現,不能抽走的竹籤都是因為在環中。所以我們統計一下一個點的入度。

對於入度為$0$的點,我們將其放入佇列中$bfs$。當然,我們從佇列中每取出一個點,ans就要加$1$,因為這個入度為0的點是可以取走的。

同時,取出這個竹籤後,其被壓竹籤的入度也相應減$1$,如果發現入度為$0$的竹籤則繼續丟入佇列。

#include <bits/stdc++.h>
using namespace std;
#define N 1000010

inline 
int read(){ int x = 0, s = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') s = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); } return x * s; } struct node{ int v, next; } t[N]; int f[N]; int bian = 0
; inline void add(int u, int v){ t[++bian] = (node){v, f[u]}, f[u] = bian; return ; } queue <int> q; int in[N]; bool vis[N]; int ans = 0; void bfs(){ while(!q.empty()){ int now = q.front(); q.pop(); ans++; for(int i = f[now]; i; i = t[i].next){
int v = t[i].v; in[v]--; if(in[v] == 0 && !vis[v]) { vis[v] = 1; q.push(v); } } } return ; } int main(){ // freopen("mikado.in", "r", stdin); // freopen("mikado.out", "w", stdout); int n = read(), m = read(); for(int i = 1;i <= m; i++){ int x = read(), y = read(); in[y]++; add(x, y); } for(int i = 1;i <= n; i++){ if(in[i] == 0) q.push(i); // i 不在環內 } bfs(); printf("%d\n", ans); return 0; }