2 条题解

  • 0
    @ 2025-10-8 16:57:56

    缩点为有向无环图(DAG),半连通子图是一条链(不可能有分支,否则不同分支的点相互之间无法相连)

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1100;
    vector<int> G1[N], G2[N];
    int tsp, cnt, low[N], dfn[N], scc[N];
    stack<int> stk;
    bool instk[N];
    
    void tarjan(int x) {
        dfn[x] = low[x] = ++tsp;
        stk.push(x);
        instk[x] = 1;
        for (int y : G1[x]) {
            if (dfn[y] == 0) {
                tarjan(y);
                low[x] = min(low[x], low[y]);
            } else if (instk[y]) {
                low[x] = min(low[x], dfn[y]);
            }
        }
        if (low[x] == dfn[x]) {
            cnt++;
            int z;
            for (z = -1; z != x; ) {
                z = stk.top();
                stk.pop();
                instk[z] = 0;
                scc[z] = cnt;
            }
        }
    }
    
    int main() {
        int T;
        scanf("%d", &T);
        while (T--) { // 处理多组测试数据
            int n, m;
            scanf("%d%d", &n, &m);
            memset(G1, 0, sizeof(G1)); // 初始化邻接表
            for (int i = 1, x, y; i <= m; i++) {
                scanf("%d%d", &x, &y);
                G1[x].push_back(y); // 构建原图邻接表G1
            }
    
            tsp = cnt = 0; // 初始化时间戳和SCC计数
            memset(dfn, 0, sizeof(dfn));
            memset(low, 0, sizeof(low));
            memset(instk, 0, sizeof(instk));
            memset(scc, 0, sizeof(scc));
            for (int i = 1; i <= n; i++) { // 对每个未访问节点执行Tarjan算法
                if (dfn[i] == 0) tarjan(i);
            }
    
            map<pair<int, int>, bool> mp; // 避免DAG中重复边
            vector<int> rd(cnt + 1); // 记录DAG各节点入度
            memset(G2, 0, sizeof(G2)); // 初始化DAG邻接表G2
            for (int i = 1; i <= n; i++) {
                for (int j : G1[i]) { // 将原图边转化为DAG边
                    int x = scc[i], y = scc[j];
                    if (x != y && !mp[{x, y}]) { // 不同SCC且无重复边
                        G2[x].push_back(y);
                        rd[y]++;
                        mp[{x, y}] = 1;
                    }
                }
            }
    
            deque<int> q; // 用于拓扑排序
            for (int i = 1; i <= cnt; i++) {
                if (rd[i] == 0) q.push_back(i); // 入度为0的节点入队
            }
            bool flag = 1; // 标记是否为链
            while (!q.empty()) {
                if (q.size() > 1) { // 若队列中超过一个节点,说明存在分支
                    flag = 0;
                    break;
                }
                int x = q.front(); q.pop_front(); // 取出队首节点
                for (int y : G2[x]) { // 处理x的邻接节点
                    if (--rd[y] == 0) q.push_back(y); // 入度为0时入队
                }
            }
            printf("%s\n", flag ? "Yes" : "No"); // 输出结果
        }
        return 0;
    }
    
    • 0
      @ 2025-10-8 16:57:19
      //缩点为有向无环图(DAG),半连通子图是一条链(不可能有分支,否则不同分支的点相互之间无法相连) 
      #include<bits/stdc++.h>
      using namespace std;
      const int N=1100;
      vector<int>G1[N],G2[N];
      int tsp,cnt,low[N],dfn[N],scc[N];
      stack<int>stk;bool instk[N];
      void tarjan(int x)
      {
      	dfn[x]=low[x]=++tsp;
      	stk.push(x);instk[x]=1;
          for(int y:G1[x]) 
          {
              if(dfn[y]==0)
              {
                  tarjan(y);
                  low[x]=min(low[x],low[y]);
              }
              else if(instk[y])low[x]=min(low[x],dfn[y]);
          }
          if(low[x]==dfn[x]) 
          {
              cnt++;
              for(int z=-1;z!=x;)
      		{
      			z=stk.top();stk.pop();instk[z]=0;
                  scc[z]=cnt;
              }
          }
      }
      	
      int main()
      {
      	int T;scanf("%d",&T);
      	while(T--)
      	{
      		int n,m;scanf("%d%d",&n,&m);
      		memset(G1,0,sizeof(G1));
      		for(int i=1,x,y;i<=m;i++)scanf("%d%d",&x,&y),G1[x].push_back(y);
      		
      		tsp=cnt=0;memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));
      		memset(instk,0,sizeof(instk));memset(scc,0,sizeof(scc));
      		for(int i=1;i<=n;i++)if(dfn[i]==0)tarjan(i);
      		
      		map<pair<int,int>,bool>mp; vector<int>rd(cnt+1);
              memset(G2,0,sizeof(G2));
      		for(int i=1;i<=n;i++)for(int j:G1[i])
              {
                  int x=scc[i],y=scc[j];
                  if(x!=y && !mp[{x,y}]) G2[x].push_back(y),rd[y]++,mp[{x,y}]=1;
              }
      
              deque<int>q;
              for(int i=1;i<=cnt;i++)
              {
                  if(rd[i]==0)
                  {
                      q.push_back(i);
                  }
              }
              bool flag=1;
              while(!q.empty())
              {
                  if(q.size()>1){flag=0;break;}
                  int x=q.front();q.pop_front();
                  for(int y:G2[x])
                  {
                      rd[y]--;
                      if(rd[y]==0)q.push_back(y);
                  }
              }
      		if(flag) printf("Yes\n");else printf("No\n");
      	}
      	return 0;
      }
      • 1

      *【缩点】判断半连通图[POJ2762]

      信息

      ID
      1490
      时间
      1000ms
      内存
      64MiB
      难度
      8
      标签
      递交数
      270
      已通过
      39
      上传者