[HDU 5413] CRB and Roads (拓撲排序+bitset卡時)
阿新 • • 發佈:2019-02-06
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;
}