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; }