题目传送门
其实这题还是挺水的,强联通分量的正解也是比较好想的,直接上tarjan。
对于题目的第一问,只要求节点数大于1的强联通分量个数就好了。
对于题目的第二问,只要求节点数大于1且出度为0的强联通分量中的所有节点编号就行了。
小提示:这题有两个要注意的地方:
- 第二问的答案要求该强联通分量的节点数大于1。(我就是在这里WA了好多次,以后一定要注意读题,汗……)
- 还是第二问,在输出每个强联通分量中的节点编号之前记得排序。(数据坑……)
代码打的比较乱,将就着看看吧……
附上AC代码:
#include <cstdio>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;
stack <int> s;
vector <int> map[1010],scc[1010];
int n,m,x,y,d[1010],t[1010],b[1010],sy[1010],g,ans,size,cd[1010],rd[1010];
bool bo;
void so(int x){
b[x]=1,t[x]=d[x]=++size,s.push(x);
for (int i=0; i<map[x].size(); ++i)
if (!d[map[x][i]]) so(map[x][i]),t[x]=min(t[x],t[map[x][i]]);
else if (b[map[x][i]]) t[x]=min(t[x],d[map[x][i]]);
if (t[x]==d[x]){
++g;int p,sum=0;
while (!s.empty()){
p=s.top();++sum,s.pop(),b[x]=0,sy[p]=g,scc[g].push_back(p);
if (p==x) break;
}
sort(scc[g].begin(),scc[g].end());
if (sum>1) ++ans;
}
return;
}
int main(void){
scanf("%d%d",&n,&m);
for (int i=1; i<=m; ++i) scanf("%d%d",&x,&y),map[x].push_back(y);
for (int i=1; i<=n; ++i) if (!d[i]) so(i);
printf("%d\n",ans);
for (int i=1; i<=n; ++i)
for (int j=0; j<map[i].size(); ++j)
if (sy[i]!=sy[map[i][j]]) {
cd[sy[i]]+=scc[sy[map[i][j]]].size();
rd[sy[map[i][j]]]+=scc[sy[i]].size();
}
ans=0;
for (int i=1; i<=g; ++i)
if (!cd[i]){
if (ans) {bo=1;break;}
if (scc[i].size()==1) continue;
ans=i;
}
if (!ans||bo) printf("-1");
else for (int i=0; i<scc[ans].size(); ++i) printf("%d ",scc[ans][i]);
return 0;
}
写在最后:果然还是要好好读题(学好语文),没有看懂题目,一切都是扯淡……