1 solutions

  • 0
    @ 2023-11-5 16:03:36

    难度: 绿

    算法: 强连通分量,缩点

    首先对于两只牛 i,ji,j,如果 ii 喜欢 jj,则连一条自 iijj 的有向边,然后在这个图上跑强连通分量并缩点,得到有向无环图。

    在这里证明一个东西:

    一个有向无环图至少有一个节点出度为 00

    使用反证,如果没有点出度为 00

    对于第 11 个点,其至少有一条边连向别的点,不妨设其连向了第 22 个点。

    对于第 22 个点,其同样至少有一条边连向别的点,但不能连向第 11 个点,不妨设其连向了第 33 个点。

    对于第 33 个点,其仍然至少有一条边连向别的点,但不能连向第 1,21,2 个点,不妨设其连向了第 44 个点。

    ......以此类推,那么最后一个点不能连向所有的点,矛盾。所以原命题得证。

    如果有恰好一个点出度为 00,那么答案就是这个点的大小。因为其他的点上的牛都不被这个点上的牛所喜欢。而由于其他点都有出度,所以必定都喜欢这个点上的牛。

    如果有多于一个点出度为 00,那么答案就为 00,因为这两个节点上的牛互相不喜欢。

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,a,b,u;
    int l[10010],d[10010],in[10010],s[10010],c,t,p[10010],sz[10010];
    stack<int> st;
    vector<int> e[10010],k[10010];
    void tarj(int u){
    	l[u]=d[u]=++c;
    	st.push(u);
    	in[u]=1;
    	for(int i=0;i<int(e[u].size());i++){
    		int v=e[u][i];
    		if(!d[v]){
    			tarj(v);
    			l[u]=min(l[u],l[v]);
    		}
    		else if(in[v]){
    			l[u]=min(l[u],l[v]);
    		}
    	}
    	if(l[u]==d[u]){
    		t++;
    		while(1){
    			sz[t]++;
    			s[st.top()]=t;
    			in[st.top()]=0;
    			if(st.top()==u){
    				st.pop();
    				break;
    			}
    			st.pop();
    		}
    	}
    }
    int main(){
    	ios::sync_with_stdio(0);
    	cin>>n>>m;
    	for(int i=1;i<=m;i++){
    		cin>>a>>b;
    		e[a].push_back(b);
    	}
    	for(int i=1;i<=n;i++){
    		if(!d[i]) tarj(i);
    	}
    	for(int i=1;i<=n;i++){
    		for(int j=0;j<int(e[i].size());j++){
    			if(s[i]!=s[e[i][j]]) k[s[i]].push_back(s[e[i][j]]);
    		}
    	}
    	for(int i=1;i<=t;i++){
    		if(k[i].empty()) u++;
    	}
    	if(u>1){
    		cout<<0;
    		return 0; 
    	} 
    	for(int i=1;i<=t;i++){
    		if(k[i].empty()){
    			cout<<sz[i];
    			return 0;
    		}
    	}
    }
    
    • 1

    Information

    ID
    93
    Time
    1000ms
    Memory
    512MiB
    Difficulty
    8
    Tags
    # Submissions
    12
    Accepted
    9
    Uploaded By