hdu6165-tarjan&&多校9&&模板修正|XJB暴力-FFF at Valentine

69 篇文章 0 订阅
58 篇文章 0 订阅

http://acm.hdu.edu.cn/showproblem.php?pid=6165
坑啊,我以前的模板是树上的tarjan,
给定一个图,要求是否存在两个点不能到达(任意一个到达任意一个都算到达)。如果存在,就输出那个长长的矫情的情话。
否则就输出那个短短的情话。
边是有向边。因为题目说了不能返回

没有找到一个 scc时,没有把栈里的标记都给置0.。
然后我就感觉那么多人都过了,不应该是这个玩意,毕竟他比较冷门。。。
修正了 模板,还有就是这个题稍微麻烦一点,得重新见图缩点。
。。缩点后 拓扑我已经想到了(因为他要两者任意就行,我就想到了用拓扑关系表示),但是当时就是模板错了qwq。。
wa了几次,scc没有 置0.。

 #include <iostream>
#include <cstdio>
#include <cstdlib>
#include <stack>
#include <vector>
#include <cstring>
#include <bits/stdc++.h>
/* 坑啊,以前没有好好准备tarjan模板,我的模板是树上用的,
不够专业,所以图上开始用就错了,。
并且当时有点乱,我感觉很多人都写了,肯定不是tarjan了。
结果还真是。。


*/
using namespace std;
const int maxn=500000;
int dfn[maxn];//dfs顺序。和一种求lca的序不一样??
int low[maxn];//最小能够到达的点。
int index1;//记录时间的标号
bool state[maxn];//是否在栈里.
stack<int>s;
vector<int>G[maxn];
vector<int>g[maxn];
int cnt[maxn];
int num[maxn];
int scc;
int vis[maxn];
void tarjan(int u)// 万能板 tarjan 处理强连通分量。
{  dfn[u]=low[u]=++index1;// 
   s.push(u);
   state[u]=true;
   for(int i=0;i<G[u].size();i++){
       int w=G[u][i];
       if(!dfn[w]){
          tarjan(w);
          low[u]=min(low[w],low[u]);
       }
       else if(state[w])
         low[u]=min(low[u],dfn[w]);//在次遇见你。。
   }
   if(low[u]==dfn[u])
    {
        scc++;
        for(;;)
        {
            int x = s.top();s.pop();
            cnt[x]=scc;
            num[scc]++;
            state[x]=false;//其实就是少了这一句。。。
            if(x==u)break;
        }
    }
}

int main()
{   //freopen("f:\\ttt\\1005.txt","r",stdin);
    //freopen("f:\\ttt\\out1.txt","w",stdout);
    int t;
    int a,m,b;
    int ttt;
     int du[maxn];
   scanf("%d",&ttt);
   while(ttt--){
        for(int i=0;i<maxn;i++){
            G[i].clear();
            g[i].clear();
        }
    scanf("%d%d",&t,&m);
    memset(du,0,sizeof(du));
    for(int i=1;i<=m;i++){
        scanf("%d%d",&a,&b);
        G[a].push_back(b);
    }
    scc=0;
    memset(state,false,sizeof(state));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(cnt,0,sizeof(cnt));
    memset(vis,false,sizeof(vis));
    memset(num,0,sizeof(num));
    while(!s.empty())
        s.pop();
    for(int i=1;i<=t;i++)
         if(!dfn[i]){
       //memset(vis,false,sizeof(vis));
       tarjan(i);
       }
        for(int i=1;i<=t;i++){
          a=cnt[i];
        for(int j=0;j<G[i].size();j++){
               b=cnt[G[i][j]];
            if(a!=b){
                g[a].push_back(b);
                du[b]++;//有出度
                //cout<<a<<"!!"<<b<<endl;
            }
        }
    }
  bool flag=false;
  queue<int>qq;
  while(!qq.empty()) qq.pop();
   int sizz=0;
   for(int i=1;i<=scc;i++){
       //cout<<du[i]<<endl;
       if(!du[i]){
       qq.push(i);
       sizz++;// 这个是判断 开始是否有两个,如果这样也是不行的。
       }
   }
   if(sizz>=2) {
        //cout<<"??"<<endl;
        flag=true;}
   while(!qq.empty()&&!flag){
         int u=qq.front();
          qq.pop();
          int siz=0;
          for(int i=0;i<g[u].size()&&!flag;i++){
              int to=g[u][i];
              du[to]--;
              if(du[to]==0){
                siz++;
                qq.push(to);
                }
             if(siz>=2) flag=true;
          }
          if(flag) break;

   }

   if(flag)
    puts("Light my fire!");
   else
    puts("I love you my love and our love save us!");
   }
    return 0;
}

又看了大佬的写法。暴力搜索每个点,因为题目说不能返回,在就创造一个正向图,一个反向图。然后每个点枚举搜索。。
为啥要正向反向呢,正向意味着他能到其他点,反向意味着其他点能到他,如果两种方法都到不了,说明他们没有缘分,只能此恨绵绵无绝期了。而如果有一种能到就算。。 大佬太强了,还是河南的,真是我河南之福

 #include <bits/stdc++.h>
using namespace std;
/* 偶然看到大佬的做法,
   我tm醉了。
   直接搜索正向图,和反向图。
   如果有不连接的,就不行。
*/
const int maxn=1e4+1000;
vector<int>G[maxn];
vector<int>v[maxn];
bool vis1[maxn];
bool vis2[maxn];
void dfs1(int u){
     vis1[u]=true;
     for(int i=0;i<G[u].size();i++){
         int to=G[u][i];
         if(!vis1[to]){
            dfs1(to);
         }
     }
}
void dfs2(int u){
     vis2[u]=true;
     for(int i=0;i<v[u].size();i++){
          int to=v[u][i];
          if(!vis2[to]){
            dfs2(to);
          }
     }
}
int main()
{   int t,m,n,a,b;
    scanf("%d",&t);
    while(t--){
          for(int i=0;i<maxn;i++){
            G[i].clear();
            v[i].clear();
          }
          scanf("%d%d",&m,&n);
          for(int i=0;i<n;i++){
              scanf("%d%d",&a,&b);
             G[a].push_back(b);
             v[b].push_back(a);
          }
          bool flag=false;
          for(int i=1;i<=m&&!flag;i++){
              memset(vis1,false,sizeof(vis1));
              memset(vis2,false,sizeof(vis2));
              dfs1(i);
              dfs2(i);
              for(int i=1;i<=m&&!flag;i++){
                 if(!vis1[i]&&!vis2[i]){
                    flag=true;
                 }
              }
          }
          if(!flag)
            puts("I love you my love and our love save us!");
          else
            puts("Light my fire!");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值