题目描述
题解
首先Tarjan缩点。
Q1:求最少人数,即入度为0的点的个数。
Q2:求最小花费,需要记录每个点的最小花费,然后求入度为0的点的最小花费之和。
这个不用特判!MDZZ
代码
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int max_n=105;
int n,x,N,calc,cnt,temp,ans1,ans2;
int Dfn[max_n],Low[max_n],vis[max_n],strack[max_n],belong[max_n],in[max_n],out[max_n];
bool a[max_n][max_n];
inline void tarjan(int now){
Dfn[now]=Low[now]=++N; vis[now]=1; strack[++temp]=now;
for (int i=1;i<=n;++i)
if (a[now][i]){
if (!Dfn[i]){
tarjan(i);
Low[now]=min(Low[now],Low[i]);
}
else if (vis[i]) Low[now]=min(Low[now],Dfn[i]);
}
if (Dfn[now]==Low[now]){
++cnt;
while (strack[temp]!=now) belong[strack[temp]]=cnt,vis[strack[temp]]=0,temp--;
belong[strack[temp]]=cnt,vis[strack[temp]]=0,temp--;
}
}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;++i){
while (~scanf("%d",&x)){
if (!x) break;
if (i!=x) a[i][x]=true;
}
}
for (int i=1;i<=n;++i)
if (!Dfn[i]) tarjan(i);
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
if (a[i][j]&&belong[i]!=belong[j]) out[belong[i]]++,in[belong[j]]++;
for (int i=1;i<=cnt;++i){
if (in[i]==0) ans1++;
if (out[i]==0) ans2++;
}
if (cnt==1) printf("1\n0\n");
else{
printf("%d\n",ans1);
printf("%d\n",max(ans1,ans2));
}
}
总结
再有手残脑残自断双手。