有向图的强连通分量
POJ 1236 - Network of Schools(基础)
http://acm.pku.edu.cn/JudgeOnline/problem?id=1236
题意:问添加多少边可成为完全连通图
解法:缩点,看度数
/** head-file **/
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <list>
#include <set>
#include <map>
#include <algorithm>
/** define-for **/
#define REP(i, n) for (int i=0;i<int(n);++i)
#define FOR(i, a, b) for (int i=int(a);i<int(b);++i)
#define DWN(i, b, a) for (int i=int(b-1);i>=int(a);--i)
#define REP_1(i, n) for (int i=1;i<=int(n);++i)
#define FOR_1(i, a, b) for (int i=int(a);i<=int(b);++i)
#define DWN_1(i, b, a) for (int i=int(b);i>=int(a);--i)
#define REP_N(i, n) for (i=0;i<int(n);++i)
#define FOR_N(i, a, b) for (i=int(a);i<int(b);++i)
#define DWN_N(i, b, a) for (i=int(b-1);i>=int(a);--i)
#define REP_1_N(i, n) for (i=1;i<=int(n);++i)
#define FOR_1_N(i, a, b) for (i=int(a);i<=int(b);++i)
#define DWN_1_N(i, b, a) for (i=int(b);i>=int(a);--i)
/** define-useful **/
#define clr(x,a) memset(x,a,sizeof(x))
#define sz(x) int(x.size())
#define see(x) cerr<<#x<<" "<<x<<endl
#define se(x) cerr<<" "<<x
/** test **/
#define Display(A, n, m) { \
REP(i, n){ \
REP(j, m) cout << A[i][j] << " "; \
cout << endl; \
} \
}
#define Display_1(A, n, m) { \
REP_1(i, n){ \
REP_1(j, m) cout << A[i][j] << " "; \
cout << endl; \
} \
}
using namespace std;
/** typedef **/
typedef long long LL;
/** Add - On **/
const int direct4[4][2]={ {0,1},{1,0},{0,-1},{-1,0} };
const int direct8[8][2]={ {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
const int direct3[6][3]={ {1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1} };
const int MOD = 1000000007;
const int INF = 0x3f3f3f3f;
const long long INFF = 1LL << 60;
const double EPS = 1e-9;
const double OO = 1e15;
const double PI = acos(-1.0); //M_PI;
const int maxn=111111;
const int maxm=511111;
int n,m;
struct EDGENODE{
int to;
int w;
int next;
};
struct SGRAPH{
int head[maxn];
EDGENODE edges[maxm];
int edge;
void init()
{
clr(head,-1);
edge=0;
}
void addedge(int u,int v,int c=1)
{
edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
}
int pre[maxn],lowlink[maxn],sccno[maxn],scc_cnt,dfs_clock;
stack<int>stk;
void dfs(int u)
{
pre[u]=lowlink[u]=++dfs_clock;
stk.push(u);
for (int i=head[u];i!=-1;i=edges[i].next){
int v=edges[i].to;
if (!pre[v]){
dfs(v);
lowlink[u]=min(lowlink[u],lowlink[v]);
} else if (!sccno[v]){
lowlink[u]=min(lowlink[u],pre[v]);
}
}
if (lowlink[u]==pre[u]){
scc_cnt++;
int x;
do{
x=stk.top();
stk.pop();
sccno[x]=scc_cnt;
}while (x!=u);
}
}
void find_scc(int n)
{
dfs_clock=scc_cnt=0;
clr(sccno,0);
clr(pre,0);
while (!stk.empty()) stk.pop();
REP_1(i,n) if (!pre[i]) dfs(i);
}
};
SGRAPH solver;
bool mp[111][111];
int main()
{
int ans1,ans2;
int idd,odd;
while (~scanf("%d",&n))
{
clr(mp,0);
solver.init();
REP_1(i,n)
{
int xt;
while (~scanf("%d",&xt))
{
if (xt==0) break;
solver.addedge(i,xt);
}
}
solver.find_scc(n);
REP(u,n)
{
for (int i=solver.head[u];i!=-1;i=solver.edges[i].next)
{
int v=solver.edges[i].to;
if (solver.sccno[u]!=solver.sccno[v])
{
mp[solver.sccno[u]][solver.sccno[v]]=true;
}
}
}
//Display_1(mp,solver.scc_cnt,solver.scc_cnt);
ans1=ans2=0;
m=solver.scc_cnt;
REP_1(i,m)
{
idd=0;
odd=0;
REP_1(j,m)
{
if (mp[j][i]) idd++;
if (mp[i][j]) odd++;
}
if (!idd) ans1++;
if (!odd) ans2++;
}
ans2=max(ans1,ans2);
if (m==1) ans2=0;
printf("%d\n%d\n",ans1,ans2);
}
return 0;
}
POJ 2553 - The Bottom of a Graph(基础)
找出度为零的强连通分量,把符合条件的点都输出出来。
/** head-file **/
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <list>
#include <set>
#include <map>
#include <algorithm>
/** define-for **/
#define REP(i, n) for (int i=0;i<int(n);++i)
#define FOR(i, a, b) for (int i=int(a);i<int(b);++i)
#define DWN(i, b, a) for (int i=int(b-1);i>=int(a);--i)
#define REP_1(i, n) for (int i=1;i<=int(n);++i)
#define FOR_1(i, a, b) for (int i=int(a);i<=int(b);++i)
#define DWN_1(i, b, a) for (int i=int(b);i>=int(a);--i)
#define REP_N(i, n) for (i=0;i<int(n);++i)
#define FOR_N(i, a, b) for (i=int(a);i<int(b);++i)
#define DWN_N(i, b, a) for (i=int(b-1);i>=int(a);--i)
#define REP_1_N(i, n) for (i=1;i<=int(n);++i)
#define FOR_1_N(i, a, b) for (i=int(a);i<=int(b);++i)
#define DWN_1_N(i, b, a) for (i=int(b);i>=int(a);--i)
/** define-useful **/
#define clr(x,a) memset(x,a,sizeof(x))
#define sz(x) int(x.size())
#define see(x) cerr<<#x<<" "<<x<<endl
#define se(x) cerr<<" "<<x
#define pb push_back
#define mp make_pair
/** test **/
#define Display(A, n, m) { \
REP(i, n){ \
REP(j, m) cout << A[i][j] << " "; \
cout << endl; \
} \
}
#define Display_1(A, n, m) { \
REP_1(i, n){ \
REP_1(j, m) cout << A[i][j] << " "; \
cout << endl; \
} \
}
using namespace std;
/** typedef **/
typedef long long LL;
/** Add - On **/
const int direct4[4][2]={ {0,1},{1,0},{0,-1},{-1,0} };
const int direct8[8][2]={ {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
const int direct3[6][3]={ {1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1} };
const int MOD = 1000000007;
const int INF = 0x3f3f3f3f;
const long long INFF = 1LL << 60;
const double EPS = 1e-9;
const double OO = 1e15;
const double PI = acos(-1.0); //M_PI;
const int maxn=111111;
const int maxm=511111;
int n,m;
struct EDGENODE{
int to;
int w;
int next;
};
struct SGRAPH{
int head[maxn];
EDGENODE edges[maxm];
int edge;
void init()
{
clr(head,-1);
edge=0;
}
void addedge(int u,int v,int c=0)
{
edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
}
int pre[maxn],lowlink[maxn],sccno[maxn],scc_cnt,dfs_clock;
stack<int>stk;
void dfs(int u)
{
pre[u]=lowlink[u]=++dfs_clock;
stk.push(u);
for (int i=head[u];i!=-1;i=edges[i].next){
int v=edges[i].to;
if (!pre[v]){
dfs(v);
lowlink[u]=min(lowlink[u],lowlink[v]);
} else if (!sccno[v]){
lowlink[u]=min(lowlink[u],pre[v]);
}
}
if (lowlink[u]==pre[u]){
scc_cnt++;
int x;
do{
x=stk.top();
stk.pop();
sccno[x]=scc_cnt;
}while (x!=u);
}
}
void find_scc(int n)
{
dfs_clock=scc_cnt=0;
clr(sccno,0);
clr(pre,0);
while (!stk.empty()) stk.pop();
REP_1(i,n) if (!pre[i]) dfs(i);
}
}solver;
bool a[5555][5555];
vector<int>ans;
vector<int>ot;
int main()
{
while (~scanf("%d",&n))
{
if (n==0) break;
scanf("%d",&m);
clr(a,0);
solver.init();
while (m--)
{
int x,y;
scanf("%d%d",&x,&y);
solver.addedge(x,y);
}
solver.find_scc(n);
m=solver.scc_cnt;
REP_1(u,n)
{
for (int i=solver.head[u];i!=-1;i=solver.edges[i].next)
{
int v=solver.edges[i].to;
if (solver.sccno[u]!=solver.sccno[v])
{
a[solver.sccno[u]][solver.sccno[v]]=true;
}
}
}
ans.clear();
REP_1(i,m)
{
int sum=0;
REP_1(j,m)
{
if (a[i][j]) sum++;
}
if (sum==0) ans.push_back(i);
}
ot.clear();
REP(k,sz(ans))
REP_1(i,n)
if (solver.sccno[i]==ans[k]) ot.push_back(i);
sort(ot.begin(),ot.end());
REP(i,sz(ot)-1)
{
cout<<ot[i]<<" ";
}
cout<<ot[sz(ot)-1]<<endl;
}
return 0;
}
POJ 2762 - Going from u to v or from v to u?(中等)
http://acm.pku.edu.cn/JudgeOnline/problem?id=2762题意:单向连通图判定
解法:缩点 + dp找最长链
/** head-file **/
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <list>
#include <set>
#include <map>
#include <algorithm>
/** define-for **/
#define REP(i, n) for (int i=0;i<int(n);++i)
#define FOR(i, a, b) for (int i=int(a);i<int(b);++i)
#define DWN(i, b, a) for (int i=int(b-1);i>=int(a);--i)
#define REP_1(i, n) for (int i=1;i<=int(n);++i)
#define FOR_1(i, a, b) for (int i=int(a);i<=int(b);++i)
#define DWN_1(i, b, a) for (int i=int(b);i>=int(a);--i)
#define REP_N(i, n) for (i=0;i<int(n);++i)
#define FOR_N(i, a, b) for (i=int(a);i<int(b);++i)
#define DWN_N(i, b, a) for (i=int(b-1);i>=int(a);--i)
#define REP_1_N(i, n) for (i=1;i<=int(n);++i)
#define FOR_1_N(i, a, b) for (i=int(a);i<=int(b);++i)
#define DWN_1_N(i, b, a) for (i=int(b);i>=int(a);--i)
/** define-useful **/
#define clr(x,a) memset(x,a,sizeof(x))
#define sz(x) int(x.size())
#define see(x) cerr<<#x<<" "<<x<<endl
#define se(x) cerr<<" "<<x
#define pb push_back
#define mp make_pair
/** test **/
#define Display(A, n, m) { \
REP(i, n){ \
REP(j, m) cout << A[i][j] << " "; \
cout << endl; \
} \
}
#define Display_1(A, n, m) { \
REP_1(i, n){ \
REP_1(j, m) cout << A[i][j] << " "; \
cout << endl; \
} \
}
using namespace std;
/** typedef **/
typedef long long LL;
/** Add - On **/
const int direct4[4][2]={ {0,1},{1,0},{0,-1},{-1,0} };
const int direct8[8][2]={ {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
const int direct3[6][3]={ {1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1} };
const int MOD = 1000000007;
const int INF = 0x3f3f3f3f;
const long long INFF = 1LL << 60;
const double EPS = 1e-9;
const double OO = 1e15;
const double PI = acos(-1.0); //M_PI;
const int maxn=1111;
const int maxm=11111;
int n,m;
struct EDGENODE{
int to;
int w;
int next;
};
struct SGRAPH{
int head[maxn];
EDGENODE edges[maxm];
int edge;
void init()
{
clr(head,-1);
edge=0;
}
void addedge(int u,int v,int c=0)
{
edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
}
int pre[maxn],lowlink[maxn],sccno[maxn],scc_cnt,dfs_clock;
stack<int>stk;
void dfs(int u)
{
pre[u]=lowlink[u]=++dfs_clock;
stk.push(u);
for (int i=head[u];i!=-1;i=edges[i].next){
int v=edges[i].to;
if (!pre[v]){
dfs(v);
lowlink[u]=min(lowlink[u],lowlink[v]);
} else if (!sccno[v]){
lowlink[u]=min(lowlink[u],pre[v]);
}
}
if (lowlink[u]==pre[u]){
scc_cnt++;
int x;
do{
x=stk.top();
stk.pop();
sccno[x]=scc_cnt;
}while (x!=u);
}
}
void find_scc(int n)
{
dfs_clock=scc_cnt=0;
clr(sccno,0);
clr(pre,0);
while (!stk.empty()) stk.pop();
REP_1(i,n) if (!pre[i]) dfs(i);
}
}solver;
bool a[maxn][maxn];
bool topsort()
{
int idd[maxn];
int cnt=0;
queue<int>que;
clr(idd,0);
REP_1(i,m)
{
REP_1(j,m)
{
if (a[j][i]) idd[i]++;
}
if (idd[i]==0) que.push(i);
}
if (que.size()>1) return false;
while (!que.empty())
{
int u=que.front();
que.pop();
cnt=0;
REP_1(v,m)
{
if (a[u][v])
{
idd[v]--;
if (idd[v]==0) {que.push(v);cnt++;};
}
}
if (cnt>1) return false;
}
return true;
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&n,&m);
solver.init();
REP(i,m)
{
int x,y;
scanf("%d%d",&x,&y);
solver.addedge(x,y);
}
solver.find_scc(n);
m=solver.scc_cnt;
clr(a,0);
REP_1(u,n)
{
for (int i=solver.head[u];i!=-1;i=solver.edges[i].next)
{
int v=solver.edges[i].to;
if (solver.sccno[u]==solver.sccno[v]) continue;
a[solver.sccno[u]][solver.sccno[v]]=true;
}
}
if (topsort()) puts("Yes");
else puts("No");
}
return 0;
}
无向图的双连通分量
POJ 3352 - Road Construction(中等)
http://acm.pku.edu.cn/JudgeOnline/problem?id=3352题意:添加多少条边可成为双向连通图
解法:把割边分开的不同分量缩点构树,看入度
建议对比下1236,有向图添加多少条边变成强连通图
/** head-file **/
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <list>
#include <set>
#include <map>
#include <algorithm>
/** define-for **/
#define REP(i, n) for (int i=0;i<int(n);++i)
#define FOR(i, a, b) for (int i=int(a);i<int(b);++i)
#define DWN(i, b, a) for (int i=int(b-1);i>=int(a);--i)
#define REP_1(i, n) for (int i=1;i<=int(n);++i)
#define FOR_1(i, a, b) for (int i=int(a);i<=int(b);++i)
#define DWN_1(i, b, a) for (int i=int(b);i>=int(a);--i)
#define REP_N(i, n) for (i=0;i<int(n);++i)
#define FOR_N(i, a, b) for (i=int(a);i<int(b);++i)
#define DWN_N(i, b, a) for (i=int(b-1);i>=int(a);--i)
#define REP_1_N(i, n) for (i=1;i<=int(n);++i)
#define FOR_1_N(i, a, b) for (i=int(a);i<=int(b);++i)
#define DWN_1_N(i, b, a) for (i=int(b);i>=int(a);--i)
/** define-useful **/
#define clr(x,a) memset(x,a,sizeof(x))
#define sz(x) int(x.size())
#define see(x) cerr<<#x<<" "<<x<<endl
#define se(x) cerr<<" "<<x
#define pb push_back
#define mp make_pair
/** test **/
#define Display(A, n, m) { \
REP(i, n){ \
REP(j, m) cout << A[i][j] << " "; \
cout << endl; \
} \
}
#define Display_1(A, n, m) { \
REP_1(i, n){ \
REP_1(j, m) cout << A[i][j] << " "; \
cout << endl; \
} \
}
using namespace std;
/** typedef **/
typedef long long LL;
/** Add - On **/
const int direct4[4][2]={ {0,1},{1,0},{0,-1},{-1,0} };
const int direct8[8][2]={ {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
const int direct3[6][3]={ {1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1} };
const int MOD = 1000000007;
const int INF = 0x3f3f3f3f;
const long long INFF = 1LL << 60;
const double EPS = 1e-9;
const double OO = 1e15;
const double PI = acos(-1.0); //M_PI;
const int maxn=1111;
const int maxm=5111;
int n,m;
struct EDGENODE{
int to;
int w;
bool cut;
int next;
};
struct SEDGE{
int u;
int v;
SEDGE(int uu=0,int vv=0){u=uu;v=vv;}
};
struct BCC_GRAPH{
int head[maxn];
EDGENODE edges[maxm];
int edge;
void init()
{
clr(head,-1);
edge=0;
}
void addedge(int u,int v,int c=0)
{
edges[edge].cut=0,edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
}
//BCC_Tarjan
int dfn[maxn],low[maxn],bccno[maxn],dfs_clock,bcc_cnt;
bool iscut[maxn];
vector<int>bcc[maxn];
stack<SEDGE>stk;
int dfs(int u,int fa)
{
int lowu=dfn[u]=++dfs_clock;
int child=0;
for (int i=head[u];i!=-1;i=edges[i].next)
{
int v=edges[i].to;
if (v==fa) continue;
SEDGE e=SEDGE(u,v);
if (!dfn[v])
{
stk.push(e);
child++;
int lowv=dfs(v,u);
lowu=min(lowu,lowv);
if (dfn[u]<=lowv) //cut 割点
{
iscut[u]=true;
//done 点双连通
bcc_cnt++;
bcc[bcc_cnt].clear();
SEDGE x;
do{
x=stk.top();
stk.pop();
if (bccno[x.u]!=bcc_cnt)
{
bcc[bcc_cnt].push_back(x.u);
bccno[x.u]=bcc_cnt;
}
if (bccno[x.v]!=bcc_cnt)
{
bcc[bcc_cnt].push_back(x.v);
bccno[x.v]=bcc_cnt;
}
}while (x.u!=u||x.v!=v);
//over
}
if (dfn[u]<lowv) //cut 桥
{
edges[i].cut=true;
edges[i^1].cut=true;
}
}
else if (dfn[v]<dfn[u])
{
stk.push(e);//done
lowu=min(lowu,dfn[v]);
}
}
if (fa<0&&child==1) iscut[u]=0;
low[u]=lowu;
return lowu;
}
void find_bcc(int n)
{
while (!stk.empty()) stk.pop();
clr(dfn,0);
clr(iscut,0);
clr(bccno,0);
dfs_clock=bcc_cnt=0;
REP_1(i,n)
{
if (!dfn[i]) dfs(i,-1);
}
}
//another
int block[maxn];
int vis[maxn];
int b_num;
void b_dfs(int u)
{
vis[u]=true;
block[u]=b_num;
for (int i=head[u];i!=-1;i=edges[i].next)
{
if (edges[i].cut) continue;
int v=edges[i].to;
if (!vis[v]) b_dfs(v);
}
}
void find_block(int n)
{
//find_block 边双连通
clr(block,0);
clr(vis,0);
b_num=0;
REP_1(i,n)
{
if (!vis[i])
{
b_num++;
b_dfs(i);
}
}
}
}solver;
bool a[maxn][maxn];
int main()
{
while (~scanf("%d%d",&n,&m))
{
clr(a,0);
solver.init();
REP(i,m)
{
int x,y;
scanf("%d%d",&x,&y);
solver.addedge(x,y);
solver.addedge(y,x);
}
solver.find_bcc(n);
solver.find_block(n);
REP_1(u,n)
{
for (int i=solver.head[u];i!=-1;i=solver.edges[i].next)
{
int v=solver.edges[i].to;
if ( solver.block[u]!=solver.block[v] )
{
a[ solver.block[u] ][ solver.block[v] ]=true;
a[ solver.block[v] ][ solver.block[u] ]=true;
}
}
}
int ans=0;
REP_1(i,solver.b_num)
{
int tmp=0;
REP_1(j,solver.b_num)
{
if (a[i][j]) tmp++;
}
if (tmp==1) ans++;
}
//Display_1(a,solver.b_num,solver.b_num);
ans=(ans+1)/2;
printf("%d\n",ans);
}
return 0;
}