1. 程式人生 > >[HDU 5413] CRB and Roads (拓撲排序+bitset卡時)

[HDU 5413] CRB and Roads (拓撲排序+bitset卡時)

HDU - 5413

求問一個有向無環圖內有多少個冗餘邊
冗餘邊的定義為,對於一條邊 (u,v)
如果刪去這條邊,u依舊能到v,則此邊是冗餘邊

這道題看起來不可做的樣子,看了下題解是暴力
對於每個點記錄一下有哪些點可以到達這個點
由於是有向無環圖,所以可以進行一個拓撲排序來解決

求完之後,對於每個點,將其前驅按拓撲序排序
從前驅拓撲序大的開始處理,如果處理到一條邊
發現其前驅在這條邊之前已經可達此點,說明這是冗餘邊

那麼問題就來了,如何求這個可達矩陣而不超時呢
關鍵就是使用bitset

bitset的第 i位表示第 i個點是否能到達此點
這樣一來,看似時間複雜度是 O(N^2),空間複雜度也是 O(N^2)
但實際上 bitset把一個位元組當作了 8位,所以複雜度可以降一個級別
所以兩個複雜度都是 1e7左右,剛好能卡過

#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <map>
#include <set>
#include <queue>
#include <bitset>
using namespace std; typedef pair<int,int> Pii; typedef long long LL; typedef unsigned long long ULL; typedef double DBL; typedef long double LDBL; #define MST(a,b) memset(a,b,sizeof(a)) #define CLR(a) MST(a,0) #define Sqr(a) ((a)*(a)) const int maxn=2e4+10, maxm=1e5+10; struct Graph { int ndn, edn, last[maxn]; int
u[maxm], v[maxm], nxt[maxm]; int deg[maxn]; void init(int _n) { ndn=_n; edn=0; MST(last,-1); CLR(deg); } void adde(int _u, int _v) { u[edn]=_u; v[edn]=_v; deg[_v]++; nxt[edn]=last[_u]; last[_u]=edn++; } }; int N,M; Graph G; bitset<maxn> rech[maxn]; vector<int> invG[maxn]; int tim,topTime[maxn]; int que[5*maxn]; bool cmp(int x, int y){return topTime[x] > topTime[y];} int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); #endif int T; scanf("%d",&T); for(int ck=1; ck<=T; ck++) { scanf("%d%d", &N, &M); G.init(N); tim=0; CLR(topTime); for(int i=0; i<N; i++) invG[i].clear(); for(int i=0; i<N; i++) {rech[i].reset(); rech[i][i]=true;} for(int i=0; i<M; i++) { int u,v; scanf("%d%d", &u, &v); G.adde(u-1,v-1); } int ans=0; int head=0,tail=0; for(int i=0; i<N; i++) if(!G.deg[i]) que[tail++]=i; while(head<tail) { int u=que[head++]; topTime[u]=++tim; for(int e=G.last[u]; ~e; e=G.nxt[e]) { int v=G.v[e]; invG[v].push_back(u); G.deg[v]--; if(!G.deg[v]) que[tail++]=v; } } for(int np=0; np<tail; np++) { int u=que[np]; sort(invG[u].begin(), invG[u].end(), cmp); for(int i=0; i<(int)invG[u].size(); i++) { int v=invG[u][i]; if(rech[u][v]) ans++; rech[u] |= rech[v]; } } printf("%d\n", ans); } return 0; }