zoukankan      html  css  js  c++  java
  • Jzoj4437 线性代数与逻辑

    不要被标题迷惑了,这是个图论题目。

    我们发现,若Ai,j=1那么显然Xi,j=1,所以y[i]!=y[j]

    这时候就变成了一个类似二分图的图,若Ai,j=1我们将节点i,j连一条边表示i和j不能相等

    我们先对每个节点i拆点成i和i+n,跑一次2sat,若i和i+n可以互达,那么显然无解,否则我们要将所有的点分入两个集合并且使得两个集合大小的乘积尽可能大

    这时候就可以对于每个节点i,dfs一次,将这个节点i加入集合0或者集合1中元素较少那个,那么显然,与i连边的所有的j都要加入另一个,而所有与j相连的节点k。。。以此类推,直到每个节点都被分入集合0或者集合1

    为什么上述方法是可行的?因为如果我们发现这个图是一个二分图,那么显然一次分配过程中,分配进入集合0和集合1的点的个数差不会超过一,所以集合0和集合1

    那么答案就是两个集合大小的乘积

    #include<stdio.h>
    #include<string.h>
    #include<vector>
    using namespace std;
    vector<int> g[2010];
    int n=0,T,st[2010],c[3]; bool vis[2010],A[1010][1010];
    inline int d(int x){ return x<=n?x+n:x-n; }
    int dfs(int x){
    	vis[x]=st[x]=1;
    	if(st[d(x)]) return st[x]=0;
    	for(int i=0,z=g[x].size();i<z;++i)
    		if(!vis[g[x][i]])
    		if(!dfs(g[x][i])) return 0;
    	st[x]=0; return 1;
    }
    void dijk(int x){
    	for(int i=0,v,z=g[x].size();i<z;++i){
    		v=(g[x][i]-1)%n+1;
    		if(!st[v]){ 
    			c[st[v]=st[x]^3]++;
    			dijk(v);
    		}
    	}
    }
    void Init(){
    	memset(vis,0,sizeof vis);
    	for(int i=1;i<2010;++i) g[i].clear();
    	c[1]=c[2]=0; memset(st,0,sizeof st);
    }
    int kmp(){
    	scanf("%d",&n);
    	for(int x,i=1;i<=n;++i)
    		for(int j=1;j<=n;++j){
    			scanf("%d",A[i]+j);
    			if(A[i][j]){
    				g[i].push_back(j+n);
    				g[i+n].push_back(j);
    			}
    		}
    	for(int i=1;i<=n<<1;++i) //检查是否有解
    		if(!vis[i]&& !dfs(i)){
    			puts("-1"); return 0;
    		}
    	for(int i=1;i<=n;++i)//分配点,st[i]=1代表i在集合0,st[i]=2代表在集合1,st[i]=0代表未分配
     		if(!st[i]){
    			if(c[1]>c[2]) st[i]=2; else st[i]=1;
    			c[st[i]]++; dijk(i);
    		}
    	int ans=0;
    	for(int i=1;i<=n;++i) --st[i];
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=n;++j)
    			if(!A[i][j]&&st[i]^st[j]) ans++;
    	printf("%d
    ",ans);
    }
    int main(){ for(scanf("%d",&T);T--;Init()) kmp(); }

  • 相关阅读:
    bert中的为什么
    ROS+Ubuntu+VSCode
    致我成为社畜的第一年
    SQL实战 11.高频SQL面试题 课程订单分析系列
    SQL实战 10.高频SQL面试题 考试分数系列
    SQL实战 9.高频SQL面试题 网站访客最近登录日期系列
    SQL实战 8.异常的邮件概率 sum、count、round和case when结合
    SQL实战 7刷题通过的题目排名 row_number、 dense_rank 和rank区别
    SQL实战 6.对于employees表中,给出奇数行的first_name
    SQL实战 5.统计salary的累计和running_total
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/9477326.html
Copyright © 2011-2022 走看看