这是一道简单的强连通分量(有向图
先用链式向前星建图,然后Tarjan+缩点
看看哪些学校内部可以共享软件
以下是重点
统计有几个拓扑序入度为0的强连通分量,即为作为共享软件的母机数
有几个拓扑序出度为0的强连通分量,即至少要添加几条线路(每次将出度为0的点往入度为0的点连
#include <bits/stdc++.h>
using namespace std;
#define rep(i,n) for(int i = 1;i <= n;i++)
#define repe(i,u) for(int i = head[u];i;i = e[i].next)
const int N = 1e4 + 5;
struct edge{
int v,next;
}e[N*N];
int dfn[N],low[N],stac[N],head[N],bel[N],rudu[N],chudu[N];
int n,x,tot,cnt,ans1,ans2,top,idx;
inline void add(int u,int v){
e[++tot] = (edge){v,head[u]};
head[u] = tot;
}
bool vis[N];
void tarjan(int u){
low[u] = dfn[u] = ++cnt;
stac[++top] = u;
vis[u] = true;
repe(i,u)
if(!dfn[e[i].v]){
tarjan(e[i].v);
low[u] = min(low[u],low[e[i].v]);
}
else if(vis[e[i].v])
low[u] = min(low[u],dfn[e[i].v]);
if(low[u] == dfn[u]){
int cur;
idx++;
do {
cur = stac[top--];
vis[cur] = false;
bel[cur] = idx;
} while(cur != u);
}
}
int main(){
scanf("%d",&n);
rep(i,n){
scanf("%d",&x);
while(x){
add(i,x);
scanf("%d",&x);
}
}
rep(i,n) if(!dfn[i]) tarjan(i);
rep(i,n) repe(j,i) if(bel[i] != bel[e[j].v])
rudu[bel[e[j].v]]++,chudu[bel[i]]++;
rep(i,idx) ans1 += rudu[i] == 0,ans2 += chudu[i] == 0;
printf("%d\n%d",ans1,ans2);
return 0;
}
代码交上去了,然后获得了——81分的高分
查缺补漏
下载数据,
10
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 0
10 0
1 0
这是一个环……出度为0的点虽然有但是……不需要加边呀
特判了,交上去72分……
#include <bits/stdc++.h>
using namespace std;
#define rep(i,n) for(int i = 1;i <= n;i++)
#define repe(i,u) for(int i = head[u];i;i = e[i].next)
const int N = 105;
struct edge{
int v,next;
}e[N*N];
int dfn[N],low[N],stac[N],head[N],bel[N],rudu[N],chudu[N];
int n,x,tot,cnt,ans1,ans2,top,idx;
bool ccnt;
inline void add(int u,int v){
e[++tot] = (edge){v,head[u]};
head[u] = tot;
}
bool vis[N];
void tarjan(int u){
low[u] = dfn[u] = ++cnt;
stac[++top] = u;
vis[u] = true;
repe(i,u)
if(!dfn[e[i].v]){
tarjan(e[i].v);
low[u] = min(low[u],low[e[i].v]);
}
else if(vis[e[i].v])
low[u] = min(low[u],dfn[e[i].v]);
if(low[u] == dfn[u]){
int cur;
idx++;
do {
cur = stac[top--];
vis[cur] = false;
bel[cur] = idx;
} while(cur != u);
}
}
int main(){
scanf("%d",&n);
rep(i,n){
scanf("%d",&x);
while(x){
add(i,x);
scanf("%d",&x);
}
}
rep(i,n) if(!dfn[i]) tarjan(i);
rep(i,n) repe(j,i) if(bel[i] != bel[e[j].v])
rudu[bel[e[j].v]]++,chudu[bel[i]]++,ccnt = true;
rep(i,idx) ans1 += rudu[i] == 0,ans2 += chudu[i] == 0;
printf("%d\n%d",ans1,ccnt ? ans2 : 0);
return 0;
}
这张图长这样
没有考虑不连通的点……(谁让我靠边判断呢
#include <bits/stdc++.h>
using namespace std;
#define rep(i,n) for(int i = 1;i <= n;i++)
#define repe(i,u) for(int i = head[u];i;i = e[i].next)
const int N = 1e4 + 5;
struct edge{
int v,next;
}e[N*N];
int dfn[N],low[N],stac[N],head[N],bel[N],rudu[N],chudu[N];
int n,x,tot,cnt,ans1,ans2,top,idx,ccnt,num;
inline void add(int u,int v){
e[++tot] = (edge){v,head[u]};
head[u] = tot;
}
bool vis[N];
void tarjan(int u){
low[u] = dfn[u] = ++cnt;
stac[++top] = u;
vis[u] = true;
repe(i,u)
if(!dfn[e[i].v]){
tarjan(e[i].v);
low[u] = min(low[u],low[e[i].v]);
}
else if(vis[e[i].v])
low[u] = min(low[u],dfn[e[i].v]);
if(low[u] == dfn[u]){
int cur;
idx++;
do {
cur = stac[top--];
vis[cur] = false;
bel[cur] = idx;
} while(cur != u);
}
}
int main(){
scanf("%d",&n);
rep(i,n){
scanf("%d",&x);
while(x){
add(i,x);
scanf("%d",&x);
}
}
rep(i,n) if(!dfn[i]) tarjan(i),num++;
rep(i,n) repe(j,i) if(bel[i] != bel[e[j].v])
rudu[bel[e[j].v]]++,chudu[bel[i]]++,ccnt++;
rep(i,idx) ans1 += rudu[i] == 0,ans2 += chudu[i] == 0;
printf("%d\n%d",ans1,ccnt == 0 && num == 1 ? 0 : ans2);
return 0;
}
已经很接近正确答案了!但是……90分
再看看~制造出一组hack!
出度为0的点有2个,但是入度为0的点有3个……
要连至少3条边才能让它变成强连通分量啊!!!
AC代码:
#include <bits/stdc++.h>
using namespace std;
#define rep(i,n) for(int i = 1;i <= n;i++)
#define repe(i,u) for(int i = head[u];i;i = e[i].next)
const int N = 1e4 + 5;
struct edge{
int v,next;
}e[N*N];
int dfn[N],low[N],stac[N],head[N],bel[N],rudu[N],chudu[N];
int n,x,tot,cnt,ans1,ans2,top,idx,ccnt,num;
inline void add(int u,int v){
e[++tot] = (edge){v,head[u]};
head[u] = tot;
}
bool vis[N];
void tarjan(int u){
low[u] = dfn[u] = ++cnt;
stac[++top] = u;
vis[u] = true;
repe(i,u)
if(!dfn[e[i].v]){
tarjan(e[i].v);
low[u] = min(low[u],low[e[i].v]);
}
else if(vis[e[i].v])
low[u] = min(low[u],dfn[e[i].v]);
if(low[u] == dfn[u]){
int cur;
idx++;
do {
cur = stac[top--];
vis[cur] = false;
bel[cur] = idx;
} while(cur != u);
}
}
int main(){
scanf("%d",&n);
rep(i,n){
scanf("%d",&x);
while(x){
add(i,x);
scanf("%d",&x);
}
}
rep(i,n) if(!dfn[i]) tarjan(i),num++;
rep(i,n) repe(j,i) if(bel[i] != bel[e[j].v])
rudu[bel[e[j].v]]++,chudu[bel[i]]++,ccnt++;
rep(i,idx) ans1 += rudu[i] == 0,ans2 += chudu[i] == 0;
printf("%d\n%d",ans1,ccnt == 0 && num == 1 ? 0 : max(ans1,ans2));
return 0;
}