zoukankan      html  css  js  c++  java
  • bzoj2215[POI2011]Conspiracy

    题意

    给出n个点的一个图,要求把所有点分成两部分,一部分是一个团,一部分是一个独立集.n<=5000

    分析

    记录自己的愚蠢...
    首先考虑如何判断存在可行方案,那么每个点要么属于团,要么属于独立集,且可以根据一个点属于哪一部分推出其他某些属于哪一部分.(如果我们钦定点A属于团,那么所有和A没有连边的点都必须属于独立集,如果我们钦定点A属于独立集,那么所有和A有连边的点都必须属于团).这样的二元关系相互推导的模型自然可以转化为2-SAT.点数5000,边数5000*5000,所以需要线性的做法,跑tarjan强联通分量.
    然后我就不会怎么统计方案了,愚蠢*1
    看题解,发现有个很妙的性质:假如我们有两个不同的方案都是合法的,那么不可能存在两个不同的点u,v使得这两个点在一个方案中都在独立集里,在另一个方案中都在团里.正确性是显然的,然而没有想到.这个结论虽然简单却非常有力:只需要找出任意一个可行解,那么其他可行解都可以由这个可行解进行次数不多的修改得到.(有三种情况:把独立集中的一个点拿到团里;把团里的一个点拿到独立集里;把团里的一个点和独立集里的一个点互换),那么我们枚举所有可能的修改情况即可.
    然后我就把tarjan求强连通分量写错了.把x出栈后,我把in_stack[x]赋值为true...(应当赋值为false).愚蠢*2
    过了样例交一发,然后WA了.愚蠢*3
    发现有个if里的判断条件少加了一个!,意思全反了.改过来交,又WA了.愚蠢*4
    发现我求出来的方案不一定两个集合都非空.改过来交,又WA了.愚蠢*5
    发现我默认2SAT求出来的初始解两个集合都非空.改过来交,终于A了.
    这做题状态不行啊...

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    using namespace std;
    const int maxn=10005,maxm=25000005;
    struct edge{
      int to,next;
    }lst[maxm],lst2[maxm];int len=1,first[maxn],len2=1,first2[maxn];
    void addedge(int a,int b){
      lst[len].to=b;lst[len].next=first[a];first[a]=len++;
    }
    void addedge2(int a,int b){
      lst2[len2].to=b;lst2[len2].next=first2[a];first2[a]=len2++;
    }
    int conv(int a,int t){
      return (a<<1)|t;
    }//conv(a,1):a is spy conv(a,0):a is supply
    int n;
    bool E[maxn][maxn];
    int dfn[maxn],T,stk[maxn],top,low[maxn],belong[maxn],tot;
    bool ins[maxn];
    vector<int> scc[maxn];
    void dfs(int x){
      dfn[x]=low[x]=++T;ins[stk[top++]=x]=true;
      for(int pt=first[x];pt;pt=lst[pt].next){
        if(!dfn[lst[pt].to]){
          dfs(lst[pt].to);
          if(low[lst[pt].to]<low[x])low[x]=low[lst[pt].to];
        }else if(ins[lst[pt].to]&&dfn[lst[pt].to]<low[x])low[x]=dfn[lst[pt].to];
      }
      if(dfn[x]==low[x]){
        ++tot;
        do{
          ins[stk[--top]]=false;
          belong[stk[top]]=tot;
          scc[tot].push_back(stk[top]);
        }while(stk[top]!=x);
      }
    }
    bool twosat(){
      for(int i=2;i<=2*n+1;++i){
        if(!dfn[i])dfs(i);
      }
      for(int i=1;i<=n;++i){
        if(belong[conv(i,0)]==belong[conv(i,1)])return false;
      }
      return true;
    }
    int col[maxn],scccol[maxn];
    bool mark[maxn];
    bool toposorted[maxn];
    int seq[maxn],cnt;
    void toposort(int x){
      if(toposorted[x])return;
      for(int pt=first2[x];pt;pt=lst2[pt].next){
        toposort(lst2[pt].to);
      }
      seq[++cnt]=x;toposorted[x]=true;
    }
    void getsol(){
      for(int i=2;i<=2*n+1;++i){
        for(int pt=first[i];pt;pt=lst[pt].next){
          if(belong[i]!=belong[lst[pt].to]){
    	addedge2(belong[i],belong[lst[pt].to]);
          }
        }
      }
      for(int i=1;i<=tot;++i)toposort(i);
      for(int i=1;i<=tot;++i){
        int x=seq[i];
        if(mark[x]&&scccol[x]==0)continue;
        mark[x]=true;scccol[x]=1;
        for(vector<int>::iterator pt=scc[x].begin();pt!=scc[x].end();++pt){
          mark[belong[(*pt)^1]]=true;scccol[belong[(*pt)^1]]=0;
        }
      }
    }
    int cnt_anti[maxn],anti[maxn];
    int main(){
      scanf("%d",&n);
      for(int i=1,num,x;i<=n;++i){
        scanf("%d",&num);
        while(num--){
          scanf("%d",&x);E[i][x]=true;
        }
      }
      for(int i=1;i<=n;++i){
        for(int j=i+1;j<=n;++j){
          if(E[i][j]){
    	addedge(conv(i,1),conv(j,0));
    	addedge(conv(j,1),conv(i,0));
          }else{
    	addedge(conv(i,0),conv(j,1));
    	addedge(conv(j,0),conv(i,1));
          }
        }
      }
      if(!twosat())printf("0
    ");
      else{
        getsol();
        for(int i=1;i<=n;++i)col[i]=scccol[belong[conv(i,1)]];
        //for(int i=1;i<=n;++i)printf("%d",col[i]);
        for(int i=1;i<=n;++i){
          if(!col[i]){
    	for(int j=1;j<=n;++j){
    	  if(col[j]&&E[i][j]){
    	    anti[i]=j;cnt_anti[i]++;
    	  }
    	}
          }else{
    	for(int j=1;j<=n;++j){
    	  if((!col[j])&&(!E[i][j])){
    	    anti[i]=j;cnt_anti[i]++;
    	  }
    	}
          }
        }
        int num[2]={0,0};
        for(int i=1;i<=n;++i)num[col[i]]++;
        int ans=(num[0]!=0&&num[1]!=0);
        for(int i=1;i<=n;++i){
          if(cnt_anti[i]==0&&num[col[i]]!=1)ans++;
        }
        for(int i=1;i<=n;++i){
          for(int j=1;j<=n;++j){
    	if(col[i]&&(!col[j])){
    	  if(cnt_anti[i]==0||(cnt_anti[i]==1&&anti[i]==j)){
    	    if(cnt_anti[j]==0||(cnt_anti[j]==1&&anti[j]==i))ans++;
    	  }
    	}
          }
        }
        printf("%d
    ",ans);
      }
      return 0;
    }
    
    
  • 相关阅读:
    ORA-1034 ORACLE not available (转)
    关于命名管道
    Linux12.3 exportfs命令
    Linux12.2 NFS配置
    Linux12.1 NFS介绍
    Linux11.4 常用SQL语句、数据库备份恢复
    Linux11.3 MySQL用户管理
    ssh远程连接错误
    Internal Server Error: /api/course/coursesection/
    vue.esm.js?efeb:591 [Vue warn]: Invalid prop: type check failed for prop "data". Expected Array, got String.
  • 原文地址:https://www.cnblogs.com/liu-runda/p/7157738.html
Copyright © 2011-2022 走看看