Codeforces Round #286 (Div. 2) D.Mr. Kitayuta's Technology
看tutorial可以知道
将图形分成一个个SCC来计算,如果SCC有环,无论个数无论层数,则整个 SCC可以形成一条环,每个点都可以互相到达,如果SCC没有环,则可以根据拓扑排序形成一条链。
前者要的是n,后者要的是n-1
拓扑排序版本
有环的都不能进行拓扑排序,则不会被访问,而且通过拓扑排序之后改变的入度比如不为0
// whn6325689
// Mr.Phoebe
// http://blog.csdn.net/u013007900
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>
#include <functional>
#include <numeric>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef complex<ld> point;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;
typedef vector<int> vi;
#define CLR(x,y) memset(x,y,sizeof(x))
#define mp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define lowbit(x) (x&(-x))
#define MID(x,y) (x+((y-x)>>1))
#define eps 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LLINF 1LL<<62
template<class T>
inline bool read(T &n)
{
T x = 0, tmp = 1; char c = getchar();
while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
if(c == EOF) return false;
if(c == '-') c = getchar(), tmp = -1;
while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
n = x*tmp;
return true;
}
template <class T>
inline void write(T n)
{
if(n < 0)
{
putchar('-');
n = -n;
}
int len = 0,data[20];
while(n)
{
data[len++] = n%10;
n /= 10;
}
if(!len) data[len++] = 0;
while(len--) putchar(data[len]+48);
}
//-----------------------------------
const int MAXN = 100010;
int in[MAXN],size[MAXN],fa[MAXN],tot,n,m,head[MAXN];
int vis[MAXN],Q[MAXN];
struct node
{
int v,next;
}e[MAXN<<1];
int findfa(int x)
{
if(x!=fa[x])
fa[x] = findfa(fa[x]);
return fa[x];
}
void init()
{
CLR(head,-1);
for(int i=1;i<=n;i++)
in[i]=0,size[i]=1,fa[i]=i;
tot = 0;
}
void addedge(int a,int b)
{
e[tot].v = b;
e[tot].next = head[a];
head[a] = tot++;
}
int main()
{
int a,b;
while(read(n)&&read(m))
{
init();
for(int i=1;i<=m;i++)
{
read(a),read(b);
in[a]++;
addedge(b,a);
if(findfa(a)!=findfa(b))
{
size[ findfa(b) ] += size[findfa(a) ];
fa[findfa(a)] = findfa(b);
}
}
queue<int>q;
for(int i=1;i<=n;i++)
if(!in[i])
q.push(i);
while(!q.empty())
{
int j = q.front();q.pop();
for(int i=head[j];~i;i=e[i].next)
{
in[ e[i].v ]--;
if(! in[ e[i].v ])
q.push(e[i].v);
}
}
for(int i=1;i<=n;i++)
if(in[i])
Q[findfa(i)] = 1;
CLR(vis,0);
int ans = 0;
for(int i=1;i<=n;i++)
{
if(!vis[ findfa(i) ])
{
vis[ findfa(i) ] = 1;
if(Q[findfa(i)])
ans += size[ findfa(i) ];
else
ans+=size[ findfa(i) ]-1;
}
}
write(ans),putchar('\n');
}
return 0;
}
dfs版本(space菊苣)
暴搜环
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
int tot=0,fa[400100],link[400100],size[400100],vis[400100],ans[400100],final_ans=0,n,m;
struct rec{int num,next;}e[1000010];
void add_edge(int x,int y)
{
tot++;
e[tot].num=y;
e[tot].next=link[x];
link[x]=tot;
}
int get_fa(int x)
{
if (fa[x]==x) return x;
return fa[x]=get_fa(fa[x]);
}
void combine(int x,int y)
{
size[get_fa(x)]+=size[get_fa(y)];
fa[get_fa(y)]=get_fa(x);
}
void dfs(int x)
{
vis[x]=1;
for (int p=link[x];p;p=e[p].next)
{
if (vis[e[p].num]==1) ans[get_fa(x)]=1;
if (vis[e[p].num]==0) dfs(e[p].num);
}
vis[x]=2;
}
int main()
{
freopen("b.txt","r",stdin);
int i,a,b;
scanf("%d %d",&n,&m);
for (i=1;i<=n;i++)
{
fa[i]=i;
size[i]=1;
vis[i]=0;
}
for (i=1;i<=m;i++)
{
scanf("%d %d",&a,&b);
add_edge(a,b);
if (get_fa(a)!=get_fa(b)) combine(a,b);
}
for (i=1;i<=n;i++)
if (vis[i]==0) dfs(i);
for (i=1;i<=n;i++)
if (fa[i]==i)
{
final_ans+=ans[i];
final_ans+=size[i]-1;
}
printf("%d",final_ans);
return 0;
}
tarjan版本(space菊苣)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
int n,m,tot[4],link[4][100100],q[100100],tail=0,low[100100],dfn[100100],tot_point,tmp_ans,ans;
struct rec{int next,num;}e[3][100100];
bool flag_circle,flag_tarjan[100100],flag[100100],flag_q[100100];
void add_edge(int x,int y,int w)
{
tot[w]++;
e[w][tot[w]].num=y;
e[w][tot[w]].next=link[w][x];
link[w][x]=tot[w];
}
void tarjan(int x)
{
int p;
flag_tarjan[x]=true;
low[x]=dfn[x]=++tot_point;
q[++tail]=x;
flag_q[x]=true;
for (p=link[1][x];p;p=e[1][p].next)
{
if (!flag_tarjan[e[1][p].num])
{
tarjan(e[1][p].num);
low[x]=min(low[x],low[e[1][p].num]);
}
else
{
if (flag_q[e[1][p].num]==true)
low[x]=min(low[x],dfn[e[1][p].num]);
}
}
if (low[x]!=dfn[x]) flag_circle=true;
while (low[x]==dfn[x]&&low[q[tail]]==dfn[x])
{
flag_q[q[tail]]=false;
tail--;
}
}
void all_search(int x)
{
tmp_ans++;
flag[x]=true;
for (int p=link[2][x];p;p=e[2][p].next)
if (flag[e[2][p].num]==false)
all_search(e[2][p].num);
}
void clean()
{
memset(flag_q,0,sizeof(flag_q));
memset(flag_tarjan,0,sizeof(flag_tarjan));
memset(flag,0,sizeof(flag));
memset(e,0,sizeof(e));
memset(tot,0,sizeof(tot));
ans=0;
}
int main()
{
int x,y;
clean();
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
add_edge(x,y,1);
add_edge(y,x,2);
add_edge(x,y,2);
}
for (int i=1;i<=n;i++)
{
if (flag_tarjan[i]==false)
{
tot_point=0;
flag_circle=false;
tarjan(i);
if (flag_circle==true)
{
tmp_ans=0;
all_search(i);
ans+=tmp_ans;
}
}
}
for (int i=1;i<=n;i++)
if (flag[i]==false)
{
tmp_ans=0;
all_search(i);
ans+=tmp_ans-1;
}
printf("%d",ans);
return 0;
}