title:Transitive Closure
题目简述:给出一个有向图,求有多少组(x, y)使得x到y有一条路径并且x不等于y。
解法: 强连通分量+拓扑排序+位运算#include <stdio.h>
#include <vector>
using namespace std;
/************************
init: stop,cnt,scnt, en置0; pre[]置-1, fir[]置NULL
CALL:for(i = 0; i < n; i++) if(-1 == pre[i]) tarjan(i, n);
************************/
#define V 2505
#define E 10005
typedef vector<int> vi;
const int K=V/30+5;
struct e{
int v;
e* nxt;
}es[E];
e* fir[V];
int id[V], pre[V], low[V], s[V], stop, cnt, scnt;
int en;
int n;
int num[V], size[V], tid[V];
vi son[V], rson[V];
int has[V][K];
void tarjan(int v, int n){
int t, minc = low[v] = pre[v] = cnt++;
e* cur;
s[stop++] = v;
for(cur = fir[v]; cur ; cur = cur->nxt){
if(-1 == pre[cur->v]) tarjan(cur->v, n);
if(low[cur->v] < minc) minc = low[cur->v];
}
if(minc < low[v]){
low[v] = minc;
return;
}
do{
id[t = s[--stop]] = scnt; low[t] = n;
}while(t != v);
++scnt; //强连通分量的个数
}
inline void add_e(int u, int v){
es[en].v = v; es[en].nxt = fir[u]; fir[u] = &es[en++];
}
void getSCC(int n){ //get strongly connected component
stop = cnt = scnt = 0;
int i;
for(i = 0; i < n; i++) pre[i] = -1;
for(i = 0; i < n; i++) if(-1 == pre[i]) tarjan(i, n);
}
bool input(){
scanf("%d", &n);
int u, v, i, e;
scanf("%d", &e);
for(i = 0; i < n; i++) fir[i] = NULL;
en = 0;
while(e--){
scanf("%d%d", &u, &v);
u--; v--;
add_e(u, v);
}
return true;
}
void topu(int id){
pre[id]=0;
int v, i, s;
for(s=son[id].size(), i=0; i<s; i++){
if(pre[v=son[id][i]]==-1){
topu(v);
}
}
tid[cnt++]=id;
}
void solve(){
getSCC(n);
int i, ans, u, v, k, j, s, h, g;
e* cur;
for(i=0; i<scnt; i++){
son[i].clear();
rson[i].clear();
size[i]=0;
}
for(i=0; i<n; i++){
size[u=id[i]]++;
for(cur=fir[i]; cur; cur=cur->nxt){
if((v=id[cur->v])!=u){
son[u].push_back(v);
rson[v].push_back(u);
}
}
}
for(ans=i=0; i<scnt; i++){
ans += size[i]*(size[i]-1);
pre[i]=-1;
}
cnt=0;
k=scnt/30+(scnt%30==0 ? 0: 1);
for(i=0; i<scnt; i++){
if(pre[i]==-1){
topu(i);
}
for(j=0; j<k; j++){
has[i][j]=0;
}
}
for(i=0; i<scnt; i++){
u=tid[i];
for(s=son[u].size(), j=0; j<s; j++){
v=son[u][j];
for(h=0; h<k; h++){
has[u][h] |= has[v][h];
}
has[u][v/30] |= (1<<(v%30));
}
for(h=0; h<k; h++){
v=has[u][h];
for(g=0; v; v>>=1, g++){
if(v&1){
ans += size[u]*size[h*30+g];
}
}
}
}
printf("%d\n", ans);
}
int main(){
int t;
scanf("%d", &t);
while(t--){
input();
solve();
}
return 0;
}
暴力广搜的版本:
#include <stdio.h>
#include <vector>
using namespace std;
/************************
init: stop,cnt,scnt, en置0; pre[]置-1, fir[]置NULL
CALL:for(i = 0; i < n; i++) if(-1 == pre[i]) tarjan(i, n);
************************/
#define V 2505
#define E 10005
typedef vector<int> vi;
const int K=V/30+5;
struct e{
int v;
e* nxt;
}es[E];
e* fir[V];
int id[V], pre[V], low[V], s[V], stop, cnt, scnt;
int en;
int n;
int num[V], size[V], tid[V], que[V];
vi son[V];
int has[V][K];
void tarjan(int v, int n){
int t, minc = low[v] = pre[v] = cnt++;
e* cur;
s[stop++] = v;
for(cur = fir[v]; cur ; cur = cur->nxt){
if(-1 == pre[cur->v]) tarjan(cur->v, n);
if(low[cur->v] < minc) minc = low[cur->v];
}
if(minc < low[v]){
low[v] = minc;
return;
}
do{
id[t = s[--stop]] = scnt; low[t] = n;
}while(t != v);
++scnt; //强连通分量的个数
}
inline void add_e(int u, int v){
es[en].v = v; es[en].nxt = fir[u]; fir[u] = &es[en++];
}
void getSCC(int n){ //get strongly connected component
stop = cnt = scnt = 0;
int i;
for(i = 0; i < n; i++) pre[i] = -1;
for(i = 0; i < n; i++) if(-1 == pre[i]) tarjan(i, n);
}
bool input(){
scanf("%d", &n);
int u, v, i, e;
scanf("%d", &e);
for(i = 0; i < n; i++) fir[i] = NULL;
en = 0;
while(e--){
scanf("%d%d", &u, &v);
u--; v--;
add_e(u, v);
}
return true;
}
int BFS(int s){
int l, r, num, i, v, u, ans;
pre[s]=s;
for(ans=l=r=0, que[r++]=s; l!=r; ){
for(num=son[u=que[l++]].size(), i=0; i<num; i++){
if(pre[v=son[u][i]]!=s){
pre[v]=s;
ans+=size[s]*size[v];
que[r++]=v;
}
}
}
return ans;
}
void solve(){
getSCC(n);
int i, ans, u, v;
e* cur;
for(i=0; i<scnt; i++){
son[i].clear();
size[i]=0;
}
for(i=0; i<n; i++){
size[u=id[i]]++;
for(cur=fir[i]; cur; cur=cur->nxt){
if((v=id[cur->v])!=u){
son[u].push_back(v);
}
}
}
for(ans=i=0; i<scnt; i++){
ans += size[i]*(size[i]-1);
pre[i]=-1;
}
for(i=0; i<scnt; i++){
ans+=BFS(i);
}
printf("%d\n", ans);
}
int main(){
int t;
scanf("%d", &t);
while(t--){
input();
solve();
}
return 0;
}