hrbust 1954 哈理工oj 1954 神奇的国家【图论+邻接表+dfs】

75 篇文章 0 订阅

神奇的国家
Time Limit: 2000 MSMemory Limit: 32768 K
Total Submit: 38(12 users)Total Accepted: 12(11 users)Rating: Special Judge: No
Description


有一个由n个城市组成的国家,国王要求,每两个城市之间只能由一条单向的路相连,这样有些城市之间就不能相互到达

(A和B可以相互到达是指,从A出发可以到达B,从B出发也可以到达A),而有些城市之间就可以。你作为一个商人,想

在几个可以相互到达的城市之间贸易,那么请你求出那些城市之间是可以相互到达的。

输入数据保证有且只有一个环,但是不一定构成一些相互到达的城市。


Input


每组数据的第一行包括两个整数n和m(0≤m≤n≤2000),n表示有n个城市,并且这些城市之间有n条路相连,m表示唯

一的一个入度为0的点。接下来的n行每行有两个整数s和t,表示从城市s到城市t有一条有向的路。

每个城市最多只会有20个城市与之相连。

当n=m=0时,输入结束。


Output
每组输出包含一个行,如果存在可以相互到达的城市,那么就输出“TwIStOy is so clever.”否则输出“TwIStOy is so nb.”。
Sample Input
5 0
0 1
1 2
2 3
3 4
4 1
6 0
0 1
0 2
1 3
1 4
4 5
2 5
Sample Output

TwIStOy is so clever.

TwIStOy is so nb.


Hint
解释一下度: 度:即和这个节点相连的边的数目。 入度:即指向这个节点的边的数目。出度:即由这个点出发的边的数目。
        度 = 入度 + 出度(在有向图中)


判断是否有环存在即可。
对经过的点进行标记,如果在有该节点出发的路径上,找到了之前标记的点,则说明有环。
如果由该节点出发的所有路径都没有找到环,就把该节点的标记取消
Source
新生练习赛(2013.11.24)
Author
TwIStOy

让我们找两个点,a,b,a能到b,并且能从b到a。第一思路是floyd递推路径关系,如果i到j有路,j到k有路,那么i到k就有路,最后遍历所有边,如果map【i】【j】==1并且map【j】【i】==1表示达到目的,输出clever就行了。但是看到数据范围瞬间枪毙,2000^3,剪枝无果,TLE两发、、、然后就想用dfs找环吧,如果能从1找到2,2找到3,3找到1,那么就说明也会有满足条件出现,可惜WA,忘记几个重要的点:满足条件不一定要成环。然后最后加上一个output【】【】数组AC、

思路:

1、output【】【】二维数组保存图,如果从i到j能走的到,output【i】【j】=1。否则为0,用dfs的过程给他填补数据、

2、dfs所有点,能找到的点,一律入output【起点】【找到的点】、

3、两层for遍历,如果output【i】【j】==1&&output【j】【i】==1,输出clever、

#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
vector<int >map[2005];//邻接表
int output[2005][2005];
int vis[2005];//dfs不想找到重复的点
int ok;
int n,m;
void dfs(int qidian,int now)//简洁dfs
{
    vis[now]=1;
    output[qidian][now]=1;
    for(int i=0;i<map[now].size();i++)
    {
        int nex=map[now][i];
        if(vis[nex]==0)
        dfs(qidian,nex);
    }
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        memset(output,0,sizeof(output));
        for(int i=0;i<n;i++)
        map[i].clear();
        for(int i=0;i<n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            map[x].push_back(y);
        }
        for(int i=0;i<n;i++)
        {
            memset(vis,0,sizeof(vis));
            dfs(i,i);
        }
        ok=0;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(output[i][j]==1&&output[j][i]==1&&i!=j)
                {
                    //printf("%d %d\n",i,j);
                    ok=1;
                    break;
                }
            }
            if(ok==1)break;
        }
        if(ok==1)
        {
            printf("TwIStOy is so clever.\n");
        }
        else
        {
            printf("TwIStOy is so nb.\n");
        }
    }
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值