[JZOJ P1211] [dfs+图论]街道赛跑

@kaike

传送门

话说回来,这也是很久之前的坑辣,我终于明白了oi的真谛,就是挖出一个又一个的坑,跳进去,然后再一个一个的填回去。

输入十分坑,但是这是一个明显的坑点。

n=-1;
for(;;)
    {
        cin>>x;
        if(x==-1)   break;
        if(x==-2)   n++;
        else    e[n+1][x]=1;
    }

这样就可以愉快地算出n值辣。

第一问求什么“不可避免的路口”,也就是说少了那个点,图就不再联通。

就是一层循环,枚举每一个点然后标记为1,起点0也标记为1,dfs(0);如果某个点图不再联通,加入到答案中,排序输出。

第二问求“中间路口”,这不是一个求割点?

好像不是吧....有向图,类似于割点却又不是割点的东西。

用割点求过了两组,暴力!

 1 /*
 2 by kaike
 3 11/16/2016
 4 */
 5 #include<iostream>
 6 #include<algorithm>
 7 #include<cstring>
 8 #include<string>
 9 #include<cstdio>
10 using namespace std;
11 const int MAXN=110;
12 bool flag=0;
13 int e[60][60],x,n=-1;
14 int bok[60],ans[60],len=0;
15 int num[60],low[60],root=0,index=0,summ=0;
16 void dfs(int k)
17 {
18     if(k==n||flag==1)
19     {
20         flag=1;
21         return ;
22     }
23     for(int i=0;i<=n;i++)
24         if(bok[i]==0 && e[k][i] )
25         {
26             bok[i]=1;
27             dfs(i);
28             bok[i]=0;
29         }
30 }
31 void init()
32 {
33     for(;;)
34     {
35         cin>>x;
36         if(x==-1)   break;
37         if(x==-2)   n++;
38         else    e[n+1][x]=1;
39     }
40     for(int i=1;i<n;i++)
41     {
42         bok[i]=1;
43         bok[0]=1;
44         flag=0;
45         dfs(0);
46         bok[i]=0;
47         if(flag==0)  ans[++len]=i;
48     }
49     sort(ans+1,ans+len+1);
50     cout<<len<<' ';
51     for(int i=1;i<=len;i++)
52         cout<<ans[i]<<' ';
53     cout<<endl;
54 }
55 void dfnlow(int cur,int father)
56 {
57     int child=0;
58     index++;
59     num[cur]=index;
60     low[cur]=index;
61     for(int i=0;i<=n;i++)
62         if(e[cur][i])
63         {
64             if(num[i]==0)
65             {
66                 child++;
67                 dfnlow(i,cur);
68                 low[cur]=min(low[cur],low[i]);
69                 if(cur!=root && low[i]>=num[cur])
70                     bok[cur]=1;
71                 if(cur==root &&child==2)
72                     bok[cur]=1;
73             }
74             else if(i!=father)
75                 low[cur]=min(low[cur],num[i]);
76         }
77 }
78 void work()
79 {
80     for(int i=0;i<=n;i++)
81         for(int j=0;j<=n;j++)
82             if(e[i][j] &&i!=j)
83                 e[j][i]=1;
84     memset(bok,0,sizeof(bok));
85     memset(ans,0,sizeof(ans));
86     len=0;
87     dfnlow(0,root);
88 }
89 int main()
90 {
91     init();
92     work();
93     for(int i=0;i<=n;i++)
94         if(bok[i]==1)   cout<<i<<' ';
95     return 0;
96 }
写了快100行结果过了两组 = = 十分不爽 

正解是用两个ans数组,在第一次正向遍历的同时来一次反向遍历,标记出所能到达的路口,如果从起点出发经过的路口和从该路口出发经过的路口重合,说明这个路口不是中间路口。

---> 自从中间路口把图分成两部分,从中间路口出发和从起点出发之间经过的路口除中间路口肯定没有一样的 。  

 

posted @ 2016-11-16 16:12  kaike  阅读(150)  评论(1编辑  收藏  举报