2 条题解

  • 0
    @ 2026-9-2 18:37:02

    95分调了一个小时……

    思路

    很容易注意到如果有一个点入度大于等于22,那么一定是不行的,因为一条边只能有一个方向。但是很快就注意到样例的第四个输入并不符合我们的想法。

    不难注意到第四个输入的D图其实是同一个点上有三个自环,很明显原图的重边我们是需要排除的,所以就可以写出以下代码,十分简单(但是好像我讲的有点抽象)

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=310;
    vector<int>G[N];
    bitset<N>a[N];
    int rd[N];
    bool v[N],used[N][N];
    int main()
    {
    	int T;scanf("%d",&T);
    	while(T--)
    	{
    		memset(G,0,sizeof(G));
    		memset(a,0,sizeof(a));
    		memset(rd,0,sizeof(rd));
    		memset(v,0,sizeof(v));
    		memset(used,0,sizeof(used));
    		int n,m;scanf("%d%d",&n,&m);
    		bool flag=0;
    		for(int i=1,x,y;i<=m;i++)
    		{
    			scanf("%d%d",&x,&y);x++;y++;
    			if(used[x][y]){flag=1;}
    			used[x][y]=1;
    			G[x].push_back(y);
    			a[x][y-1]=1;rd[y]++;
    		}
    		if(flag){puts("No");continue;}
    		for(int i=1;i<=n;i++)if(!v[i])for(int j=i+1;j<=n;j++)if(a[i]==a[j]&&!v[j])
    		{
    			v[j]=1;
    			for(int w:G[j])rd[w]--;
    		}
    		bool bk=0;
    		for(int i=1;i<=n;i++)if(rd[i]>1)bk=1;
    		if(!bk)puts("Yes");
    		else puts("No");
    	}
    	return 0;
    }
    
    • 0
      @ 2026-8-27 8:00:23

      大致思路就是:如果在图 D 中:uvwu\to v\to w,又有 xvwx\to v\to w,那么在 E 中,uvuvxvxv 都向 vwvw 连边。此时如果存在另一个 yy 使得 vyv\to y 有边,则在 E 中 uvuvxvxv 都应该向 vyvy 有边。

      也就是说,两个点指向一个公共的点,那么它们所有出边指向的点集必然相同,事实上这是存在 D 的充要条件,证明不难。

      之前几篇题解要么用了并查集,要么用了数组暴力判断,这里提供一种不难想且速度不慢的方法:Bitset。

      用 Bitset 记录邻接矩阵,枚举两行,算一下两行的与和异或,如果与不为 00,则说明指向公共点,此时再看异或,如果异或不为 00,说明出边不重合,答案为 No.

      #include <bits/stdc++.h>
      using namespace std;
      const int MAXN=310;
      int t,n,m,x,y;
      bitset <MAXN> b[MAXN],tmp1,tmp2;
      int main () {
      	scanf("%d",&t);
      	for (int ii=1;ii<=t;ii++) {
      		scanf("%d%d",&n,&m);
      		for (int i=1;i<=n;i++) {b[i].reset();}
      		for (int i=1;i<=m;i++) {
      			scanf("%d%d",&x,&y);
      			x++,y++;
      			b[x].set(y);
      		}
      		int flg=0;
      		for (int i=1;i<=n;i++) {
      			if (flg) {break;}
      			for (int j=1;j<=n;j++) {
      				tmp1=b[i]&b[j],tmp2=b[i]^b[j];
      				if (tmp1.count()!=0&&tmp2.count()!=0) {flg=1;break;}
      			}
      		}
      		printf("%s\n",flg?"No":"Yes");
      	}
      	return 0;
      }
      
      • 1

      信息

      ID
      4773
      时间
      500ms
      内存
      64MiB
      难度
      10
      标签
      递交数
      11
      已通过
      2
      上传者