闲着无聊没事干,水两道辣鸡SB题。。。这种tarjan就直接vector秒杀了。。。(洛谷上也都有貌似)
1654: [Usaco2006 Jan]The Cow Prom 奶牛舞会
Time Limit: 5 Sec Memory Limit: 64 MBDescription
约翰的N(2≤N≤10000)只奶牛非常兴奋,因为这是舞会之夜!她们穿上礼服和新鞋子,别上鲜花,她们要表演圆舞.
只有奶牛才能表演这种圆舞.圆舞需要一些绳索和一个圆形的水池.奶牛们围在池边站好,顺时针顺序由1到N编号.每只奶牛都面对水池,这样她就能看到其他的每一只奶牛.为了跳这种圆舞,她们找了M(2≤M≤50000)条绳索.若干只奶牛的蹄上握着绳索的一端,绳索沿顺时针方绕过水池,另一端则捆在另一些奶牛身上.这样,一些奶牛就可以牵引另一些奶牛.有的奶牛可能握有很多绳索,也有的奶牛可能一条绳索都没有对于一只奶牛,比如说贝茜,她的圆舞跳得是否成功,可以这样检验:沿着她牵引的绳索,找到她牵引的奶牛,再沿着这只奶牛牵引的绳索,又找到一只被牵引的奶牛,如此下去,若最终能回到贝茜,则她的圆舞跳得成功,因为这一个环上的奶牛可以逆时针牵引而跳起旋转的圜舞.如果这样的检验无法完成,那她的圆舞是不成功的.
如果两只成功跳圆舞的奶牛有绳索相连,那她们可以同属一个组合.
给出每一条绳索的描述,请找出,成功跳了圆舞的奶牛有多少个组合?
Input
第1行输入N和M,接下来M行每行两个整数A和B,表示A牵引着B.
Output
成功跳圆舞的奶牛组合数.
Sample Input
5 4
2 4
3 5
1 2
4 1
INPUT DETAILS:
ASCII art for Round Dancing is challenging. Nevertheless, here is a
representation of the cows around the stock tank:
_1___
/**** \
5 /****** 2
/ /**TANK**|
\ \********/
\ \******/ 3
\ 4____/ /
\_______/
2 4
3 5
1 2
4 1
INPUT DETAILS:
ASCII art for Round Dancing is challenging. Nevertheless, here is a
representation of the cows around the stock tank:
_1___
/**** \
5 /****** 2
/ /**TANK**|
\ \********/
\ \******/ 3
\ 4____/ /
\_______/
Sample Output
1
HINT
1,2,4这三只奶牛同属一个成功跳了圆舞的组合.而3,5两只奶牛没有跳成功的圆舞
Source
这题就不要缩点,裸的模板。。。无语。。。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<stack>
#include<vector>
using namespace std;
struct node
{
int num,par;
}p[10005];
int n,m,index=1,x,y,cnt;
vector<int>v[10005];
bool vis[10005];
int ind[10005];
stack<int>s;
bool in_stack[10005];
void tarjan(int x)
{
p[x].num=index;
p[x].par=p[x].num;
index++;
vis[x]=1;
in_stack[x]=1;
s.push(x);
for(int i=0;i<v[x].size();i++)
{
if(!vis[v[x][i]])
{
tarjan(v[x][i]);
p[x].par=min(p[x].par,p[v[x][i]].par);
}
else if(in_stack[v[x][i]])
{
p[x].par=min(p[x].par,p[v[x][i]].num);
}
}
if(p[x].num==p[x].par)
{
++cnt;
int gutc=0;
int k;
do
{
k=s.top();
s.pop();
in_stack[k]=0;
gutc++;
}while(k!=x);
if(gutc==1)cnt--;
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
v[x].push_back(y);
}
for(int i=1;i<=n;i++)
{
if(!vis[i])tarjan(i);
}
printf("%d\n",cnt);
return 0;
}
1051: [HAOI2006]受欢迎的牛
Time Limit: 10 Sec Memory Limit: 162 MBDescription
每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这
种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头
牛被所有的牛认为是受欢迎的。
Input
第一行两个数N,M。 接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复,即有可
能出现多个A,B)
Output
一个数,即有多少头牛被所有的牛认为是受欢迎的。
Sample Input
3 3
1 2
2 1
2 3
1 2
2 1
2 3
Sample Output
1
HINT
100%的数据N<=10000,M<=50000
这题要缩点的思路,但不需要真正意义上的缩圈成点。
具体是找出SCC分解缩点,然后对于重构的图,出度为0的点若不是有且仅有一个,就说明没有最受欢迎的牛,反之就是此强连通分量里节点个数为ans。
自己体会下,无脑题。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<stack>
#include<vector>
using namespace std;
struct node
{
int num,par;
}p[50005];
int n,m,index=1,x,y,cnt,ans;
vector<int>v[50005];
bool vis[50005];
int ind[50005];
stack<int>s;
bool in_stack[50005];
int belong[50005],sum[50005],cntx[50005];
void tarjan(int x)
{
p[x].num=index;
p[x].par=p[x].num;
index++;
vis[x]=1;
in_stack[x]=1;
s.push(x);
for(int i=0;i<v[x].size();i++)
{
if(!vis[v[x][i]])
{
tarjan(v[x][i]);
p[x].par=min(p[x].par,p[v[x][i]].par);
}
else if(in_stack[v[x][i]])
{
p[x].par=min(p[x].par,p[v[x][i]].num);
}
}
if(p[x].num==p[x].par)
{
++cnt;
int k;
do
{
k=s.top();
s.pop();
belong[k]=cnt;
cntx[cnt]++;
in_stack[k]=0;
}while(k!=x);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
v[x].push_back(y);
}
for(int i=1;i<=n;i++)
{
if(!vis[i])tarjan(i);
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<v[i].size();j++)
{
if(belong[v[i][j]]!=belong[i])
{
sum[belong[i]]++;
}
}
}
int kkk=0;
for(int i=1;i<=cnt;i++)
{
if(!sum[i])
{
kkk++;
ans=cntx[i];
}
}
if(kkk!=1)printf("%d\n",0); else printf("%d\n",ans);
return 0;
}
滚去复习文化课期中考试了。现在感觉越来越懒得写博客发题解了,要写也都写水无脑题。。。。。。