http://poj.org/problem?id=1236
アイデア:最初の質問をする方法は他にもあります。その質問はディスクの書き込みと呼ばれ、度数をチェックしてカウントすることによって行われます。P2835はCDを書き込みます(そしてセットをチェックして一方向エッジを構築します)
この質問のアイデア:最初のタージャンは縮小します。ポイントを縮小した後、新しい画像の間に0度のポイントがいくつあるかを確認します。これが開始点として指定される最後のポイントです。
2番目の質問では、ポイントを要約した後、いくつかの状況を検討した後、次のことがわかります。
1-> 2 <---- 3
^
|
4
2 <---- 1 ------> 3
|
V
4
それぞれ0度と0度の最大のものを選択する必要があります。
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<stack>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e2+100;
typedef long long LL;
vector<LL>g[maxn];
stack<LL>s;
LL dfn[maxn],low[maxn],times=0,cnt=0,in[maxn],out[maxn];
bool inq[maxn];
LL col[maxn];///缩点
void tarjan(LL x)
{
dfn[x]=low[x]=++times;
s.push(x);inq[x]=true;
for(LL i=0;i<g[x].size();i++)
{
LL to=g[x][i];
if(!dfn[to])
{
tarjan(to);
low[x]=min(low[x],low[to]);
}
else if(inq[to])
{
low[x]=min(low[x],dfn[to]);
}
}
if(dfn[x]==low[x])
{
cnt++;
LL y;
do
{
y=s.top();
inq[y]=false;
col[y]=cnt;
s.pop();
}while(y!=x);
return;
}
}
int main(void)
{
LL n;cin>>n;
for(LL i=1;i<=n;i++)
{
LL to;
while(cin>>to&&to!=0)
{
g[i].push_back(to);
}
}
for(LL i=1;i<=n;i++)
{
if(!dfn[i]) tarjan(i);
}
if(cnt==1) cout<<1<<endl<<0<<endl;
else
{
for(LL i=1;i<=n;i++)
{
for(LL j=0;j<g[i].size();j++)
{
if(col[i]!=col[g[i][j]]) in[col[g[i][j]]]++,out[col[i]]++;
}
}
LL ans1=0;LL ans2=0;
for(LL i=1;i<=cnt;i++)
{
if(in[i]==0) ans1++;
if(out[i]==0) ans2++;
}
cout<<ans1<<endl<<max(ans1,ans2)<<endl;
}
}