zoukankan      html  css  js  c++  java
  • 北京集训TEST12——PA( Mortal Kombat)

    题目:

    Description

          有一天,有N个外星人企图入侵地球。地球派出全球战斗力最强的M个人代表人类对抗外星人。根据外星的战斗规则,每个外星人应该分别与一名地球人对战(不同的外星人要与不同的地球人对战)。如果任意一个外星人获胜,那么地球将被外星人占领。

          幸运的是,人类可以决定对战顺序,且可以决定每次对战的两名战士,但是要保证符合外星的战斗规则。

          地球有一个保护神。他能提前预知每一名地球人和每一名外星人的战斗结果。在战争开始前,保护神必须确定第一场战斗的两名战士。举个例子:假设第一场为人类A对战外星人A,但是人类A是能打败外星人B的唯一一名战士,那么即使人类A打败了外星人A,也不可避免地导致地球被外星人占领,因为外星人B将会打败他的对手。这意味着:第一场战斗中,“人类A对战外星人A”这个组合是不能选的。

          你的任务是:找出所有在第一场战斗中不能选的组合,即选择该组合会不可避免地导致地球被外星人占领。

    Input

          第一行为两个整数 N,M(1N300,NM1500) 。

          接下来N行M列是一个二进制矩阵A。 Ai,j=1 当且仅当第j个地球人能战胜第i个外星人。

    Output

          输出一个N行M列的矩阵B。若第一场战斗中,“第i个外星人与第j个地球人”是不能选的组合,Bi,j 应为1,否则 Bi,j 应为0。

    Sample Input

    【样例输入1】
    4 4
    1111
    1000
    1111
    1111
    【样例输入2】
    4 5
    10000
    10000
    10000
    10000
    【样例输入3】
    4 4
    1111
    1110
    1100
    1000

    Sample Output

    【样例输出1】
    1000
    0111
    1000
    1000
    【样例输出2】
    11111
    11111
    11111
    11111
    【样例输出3】
    1110
    1101
    1011
    0111

    HINT

    【数据范围与约定】

          子任务1(10分): N=4,M=6

          子任务2(20分): N=15,M=30

          子任务3(25分): N=300,M=300

          子任务4(45分): N=300,M=1500


    题解:

    解法:二分图最大匹配+Tarjan

    首先,题意可以转化为:去掉第i行和第j列后,判断二分图是否存在满匹配。直接暴力做可以得到30分。

    更进一步,就是判断边(i, j)是否为该二分图最大匹配的匹配边。

    考虑n = m的情况。我们可以先跑一次最大匹配,将匹配边从左向右连,非匹配边从右向左连。对新的图跑Tarjan,若左边的点i与右边的点j处于同一个强联通分量中,边(i, j)一定是最大匹配的匹配边(理由是一个强联通分量中,必能从该点出发又回到该点,而这个路线恰好是匹配边-非匹配边-匹配边……)。

    对于m > n的情况,把外星人补成m个,就可以转化为n = m的情况了。


    心得:

      以前匈牙利算法只会求其中一种情况,这个问题相当于求最大匹配的所有解:将两边数字同一跑匈牙利后跑tarjian;

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<ctime>
    #include<cctype>
    #include<cstring>
    #include<string>
    #include<algorithm>
    using namespace std;
    const int M=3005;
    int tot,fir[M],nxt[M*M],go[M*M];
    int belon[M];
    int n,m;
    int id[M],dfs[M],low[M],stack[M],top,sumid,cnt;
    bool visit[M];
    bool insta[M];
    char ma[M][M];
    inline void comb(int u,int v)
    {
      nxt[++tot]=fir[u],fir[u]=tot,go[tot]=v;
    }
    bool find(int x)
    {
      for(int i=1;i<=m;i++)
      {
        if(ma[x][i]=='1'&&!visit[i])
        {
          visit[i]=true;
          if(!belon[i]||find(belon[i]))
          {
            belon[i]=x;
            return true;
          }
        }
      }
      return false;
    }
    inline void tarjian(int u)
    {
      dfs[u]=low[u]=++cnt;
      stack[++top]=u;
      insta[u]=true;
      for(int e=fir[u];e;e=nxt[e])
      {
        int v=go[e];
        if(!dfs[v])
        {
          tarjian(v);
          low[u]=min(low[u],low[v]);
        }
        else 
          if(insta[v])
            low[u]=min(low[u],dfs[v]);
      }
      if(low[u]==dfs[u])
      {
        sumid++;
        while(stack[top]!=u)
        {
          insta[stack[top]]=false;
          id[stack[top]]=sumid;
          top--;
        }
        insta[stack[top]]=false;
        id[stack[top]]=sumid;
        top--;
      }
    }
    int main()
    {
      freopen("a.in","r",stdin);
      scanf("%d%d",&n,&m); 
      
      for(int i=1;i<=n;i++)
        scanf("%s",ma[i]+1);
      for(int i=n+1;i<=m;i++)
        for(int j=1;j<=m;j++)
          ma[i][j]='1';
      
      int temp=0;
      for(int i=1;i<=n;i++)
      {
        memset(visit,false,sizeof(visit));
        if(find(i))  temp++;
      }
      if(temp!=n)
      {
      
        for(int i=1;i<=n;i++)
        {  
          for(int j=1;j<=m;j++)
            cout<<"1";
          cout<<endl;
        }
        return 0;
      }
      else 
      {  
        int k=n+1;
        for(int i=1;i<=m;i++)
        {
          if(!belon[i])
            belon[i]=k++;
        }
      }
      for(int i=1;i<=m;i++)
        for(int j=1;j<=m;j++)
          if(ma[i][j]=='1')
          {
            if(belon[j]==i)  comb(i,j+m);
            else comb(j+m,i);
          }
      for(int i=1;i<=m*2;i++)
        if(!dfs[i])  tarjian(i); 
      for(int i=1;i<=n;i++)
      {  
        for(int j=1;j<=m;j++)
        {
          if(ma[i][j]=='1'&&(belon[j]==i||id[i]==id[j+m]))
            cout<<"0";
          else cout<<"1";
        }
        cout<<endl;
      }
      return 0;
    }
     
  • 相关阅读:
    java采用zip方式实现String的压缩和解压缩CompressStringUtil类
    java注解方式解析xml格式
    intellij 出现“Usage of API documented as @since 1.8+”的解决办法
    mac zsh环境配置java_home环境变量
    git常用命令汇总
    dubbo启动报错failed to bind nettyserver on
    mybatis,genarate自动生成代码
    sonarLint--强大的代码审查工具(插件)
    zookeeper安装与配置
    python小记
  • 原文地址:https://www.cnblogs.com/AseanA/p/6591064.html
Copyright © 2011-2022 走看看