易错点:
- 首先,可以进行缩点.
- 子任务1:缩点后入度为零的强连通分量必须要有新软件.
- 子任务2:要求加边后形成一个强连通图。可以考虑到缩点后的DAG上每个点都必须同时具有入度和出度,就可以将没有入度的点的数量记为p,没有出度的点的数量记为q;由于没有出度的点可以直接连接没有入度的点,答案即为max(p,q).
- 正确性显然.
#include<cstdio>
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int MAXN=1000010,MAXM=1000010;
struct firstEdge1{
int from,to,nxt;
}firstEdge[MAXM];
int firstHead[MAXN],firstEdgeCnt=0;
void addFirstEdge(int u,int v){
firstEdge[++firstEdgeCnt].from=u;
firstEdge[firstEdgeCnt].to=v;
firstEdge[firstEdgeCnt].nxt=firstHead[u];
firstHead[u]=firstEdgeCnt;
}
int dfn[MAXN],low[MAXN],dfnCnt=0;
bool inc[MAXN];
int stck[MAXN],c[MAXN],top=0;
int sccCnt=0;
vector<int> sccVec[MAXN];
void tarjan(int x){
low[x]=dfn[x]=++dfnCnt;
inc[x]=1;
stck[++top]=x;
for(int i=firstHead[x];i;i=firstEdge[i].nxt){
int v=firstEdge[i].to;
if(!dfn[v]){
tarjan(v);
low[x]=min(low[x],low[v]);
}else if(inc[v])low[x]=min(low[x],dfn[v]);
}
if(dfn[x]==low[x]){
int y;sccCnt++;
do{
y=stck[top--];
inc[y]=0;
c[y]=sccCnt;
sccVec[sccCnt].push_back(y);
}while(x!=y);
}
}
struct SecondEdge{
int from,to,nxt;
}secondEdge[MAXM];
int secondHead[MAXN],secondEdgeCnt=0;
void addSecondEdge(int u,int v){
secondEdge[++secondEdgeCnt].from=u;
secondEdge[secondEdgeCnt].to=v;
secondEdge[secondEdgeCnt].nxt=secondHead[secondEdgeCnt];
secondHead[u]=secondEdgeCnt;
}
int rd[MAXN],cd[MAXN];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
int tmp;
while(true){
scanf("%d",&tmp);
if(tmp==0)break;
addFirstEdge(i,tmp);
}
}
for(int i=1;i<=n;i++)
if(!low[i])tarjan(i);
for(int i=1;i<=firstEdgeCnt;i++){
int u=firstEdge[i].from;
int v=firstEdge[i].to;
if(c[u]!=c[v]){
addSecondEdge(c[u],c[v]);
rd[c[v]]++;
cd[c[u]]++;
}
}
int p=0,q=0;
for(int i=1;i<=sccCnt;i++){
if(rd[i]==0)p++;
if(cd[i]==0)q++;
}
cout<<p<<endl;
if(sccCnt==1)cout<<"0"<<endl;
else cout<<max(p,q)<<endl;
return 0;
}
正确性显然可还行
什么证明啊?应该是我们要保证所有没有入度和出度的点形成一个环,这样对于图中任意一个点,肯定可以到达所有点,对于既没有入度也没有出度的点,可以拆成两个点,一个指向另外一个,环长显然是p+q的,可以贡献的已有的边是$min(p,q)$,而$p+q-min(p,q)=max(p,q)$
构造方案就是从任意一个点出发,如果已经存在到达其他点的边,而且该点没在环上,就去,不存在就选择一个没有被访问过的点建一条新的边