zoukankan      html  css  js  c++  java
  • 题解 SP2878 【KNIGHTS

    题目链接

    Solution KNIGHTS

    题目大意:有(n)个骑士,其中有(m)对骑士相互憎恨。现在要排出若干个大小至少为(3)且为奇数的环,相互憎恨的骑士不能够相邻,问有多少个骑士不可能排入任何一个环

    二分图,点双联通分量


    分析:我们把有憎恨关系的连上边,这样相邻骑士之间必须没有连边,这样不好考虑,我们可以建出原图的补图,这样相邻骑士之间就必须有连边了。

    问题变成了有多少个点没有被任何一个奇数长度的环包含

    显而易见,如果一个点双联通分量内存在奇数长度的环,那么该点双联通分量里面所有的点都至少被一个奇数长度的环包含,不然与点双联通分量这个前提相矛盾

    因此我们只需要看每一个点双联通分量里面有没有奇数长度的环就可以了,没有奇数长度的环等价于图是二分图,因此我们跑一次二分图染色就可以了

    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <stack>
    #include <queue>
    using namespace std;
    const int maxn = 1024;
    vector<int> G[maxn],dcc[maxn];
    inline void addedge(int from,int to){G[from].push_back(to);}
    int tmp[maxn][maxn],dfn[maxn],mark[maxn],vis[maxn],low[maxn],col[maxn],can[maxn],dcc_tot,dfs_tot,n,m;
    inline void clear(){
    	for(int i = 1;i <= n;i++)G[i].clear();
    	for(int i = 1;i <= dcc_tot;i++)dcc[i].clear();
    	dcc_tot = dfs_tot = 0;
    	memset(can,0,sizeof(can));
    	memset(tmp,0,sizeof(tmp));
    	memset(dfn,0,sizeof(dfn));
    	memset(low,0,sizeof(low));
    }
    stack<int> stk;
    inline void tarjan(int u,int isroot = 1){
    	dfn[u] = low[u] = ++dfs_tot;
    	stk.push(u);
    	if(isroot && G[u].empty()){
    		dcc[++dcc_tot].push_back(u);
    		return;
    	}
    	for(int v : G[u])
    		if(!dfn[v]){
    			tarjan(v);
    			low[u] = min(low[u],low[v]);
    			if(low[v] >= dfn[u]){
    				dcc_tot++;
    				int t;
    				do{
    					t = stk.top();stk.pop();
    					dcc[dcc_tot].push_back(t);
    				}while(t != v);
    				dcc[dcc_tot].push_back(u);
    			}
    		}else low[u] = min(low[u],dfn[v]);
    }
    inline bool check(int i){
    	memset(mark,0,sizeof(mark));
    	memset(vis,0,sizeof(vis));
    	memset(col,0,sizeof(col));
    	for(int x : dcc[i])mark[x] = 1;
    	queue<int> Q;Q.push(dcc[i][0]),vis[dcc[i][0]] = 1;
    	while(!Q.empty()){
    		int u = Q.front();Q.pop();
    		for(int v : G[u]){
    			if(!mark[v])continue;
    			if(!vis[v])col[v] = col[u] ^ 1,Q.push(v),vis[v] = 1;
    			else if(col[u] == col[v])return false;
    		}
    	}
    	return true;
    }
    inline void solve(){
    	for(int u,v,i = 1;i <= m;i++)scanf("%d %d",&u,&v),tmp[u][v] = tmp[v][u] = 1;
    	for(int u = 1;u <= n;u++)
    		for(int v = u + 1;v <= n;v++)
    			if(!tmp[u][v])addedge(u,v),addedge(v,u);
    	for(int i = 1;i <= n;i++)
    		if(!dfn[i])tarjan(i);
    	int ans = n;
    	for(int i = 1;i <= dcc_tot;i++)
    		if(dcc[i].size() >= 3 && !check(i))
    			for(int x : dcc[i])can[x] = 1;
    	for(int i = 1;i <= n;i++)
    		ans -= can[i];
    	printf("%d
    ",ans);
    	clear();
    }
    int main(){
    	while(scanf("%d %d",&n,&m) && n && m)solve();
    	return 0;
    } 
    
  • 相关阅读:
    java内存溢出
    jstack命令使用
    JVM问题排查步骤
    c++指针常量和常量指针
    c++ 通讯录
    冒泡排序
    翻转数组
    敲桌子
    求一个100-999之间的水仙花数
    elasticsearch 模板的使用
  • 原文地址:https://www.cnblogs.com/colazcy/p/11799651.html
Copyright © 2011-2022 走看看