题目:

Description

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

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

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

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

Input

第一行为两个整数 N,M(1≤N≤300,N≤M≤1500) 。

接下来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;
}

转载于:https://www.cnblogs.com/AseanA/p/6591064.html

北京集训TEST12——PA( Mortal Kombat)相关推荐

  1. 北京集训:20180310

    北京集训的第一天,我完美爆零...... 这其中的经历,十分有趣呢. T1: 这题一看就是先猜一个性质然后利用他去求解. 如果我们知道怎么插入,怎么判定的话,可以线段树分治的说. 然后我猜了一个结论: ...

  2. 清北学堂----北京集训

    7月16日 集训第一天,毛晗杨给我们讲的基础算法和数论.基础算法讲了分块和三分等知识点,分块之前接触过,个人认为和莫队有一定的相似之处,都是把整个数组分为一个个大小相等的块,然后对块进行操作,每个块大 ...

  3. (2016北京集训十)【xsy1529】小Q与进位制 - 分治FFT

    题意很简单,就是求这个数... 其实场上我想出了分治fft的正解...然而不会打...然后打了个暴力fft挂了... 没啥好讲的,这题很恶心,卡常卡精度还爆int,要各种优化,有些dalao写的很复杂 ...

  4. 北京集训:20180323

    T1: 这题又是动态题面问题,一开始连求什么都没告诉你...... 当时自然没有看了,现在没人做没人改...... 官方题解: 标程: 1 #include <iostream> 2 #i ...

  5. 【2016北京集训测试赛】river

    HINT 注意是全程不能经过两个相同的景点,并且一天的开始和结束不能用同样的交通方式. [吐槽] 嗯..看到这题的想法的话..先想到了每个点的度为2,然后就有点不知所措了 隐隐约约想到了网络流,但并没 ...

  6. 【2018北京集训(六)】Lcm

    Portal --> 出错啦qwq(好吧其实是没有) Description 给定两个正整数\(n,k\),选择一些互不相同的正整数,满足这些数的最小公倍数恰好为\(n\),并且这些数的和为\( ...

  7. (2016北京集训十二)【xsy1542】疯狂求导

    题解: 这题看起来很难...但是实际上并没有想象中的那么难 第一眼看上去不会求导公式怎么办?不要紧,题目背景非常良心的给出了题目中的导数计算公式 求完导合并同类项很恶心怎么办?不要紧,样例解释说明了不 ...

  8. 2016北京集训测试赛(十三) Problem B: 网络战争

    Solution KD tree + 最小割树 转载于:https://www.cnblogs.com/ZeonfaiHo/p/7420354.html

  9. 【2016北京集训测试赛(八)】 直径 (虚树+树的直径)

    Description 注意:时限更改为4s 题解 考虑最原始的直径求法:找到离根节点(或离其他任意一点)最远的节点far1,再从far1出发找到离far1最远的节点far2,far1至far2的距离 ...

  10. 2016北京集训测试赛(九)Problem C: 狂飙突进的幻想乡

    Solution 我们发现, 对于一条路径来说, 花费总时间为\(ap + q\), 其中\(p\)和\(q\)为定值. 对于每个点, 我们有多条路径可以到达, 因此对于每个区间中的\(a\)我们可以 ...

最新文章

  1. TVM示例展示 README.md,Makefile,CMakeLists.txt
  2. 什么是奇异值?奇异值分解是什么?SVD分解详解及实战
  3. Javascript 取小数点后面N位
  4. 计算机专业哪家强,计算机专业哪家强?这4所大学水平一流,网友:都是“大佬”级别...
  5. QMarkDowner编译
  6. Qt之水平/垂直布局(QBoxLayout、QHBoxLayout、QVBoxLayout)
  7. BZOJ 2707: [SDOI2012]走迷宫( tarjan + 高斯消元 )
  8. asp.net AJAX 验证用户名是否存在 -Jquery
  9. 基于Heritrix+Lucene的搜索引擎构建(6)——搜索UI与结果页面
  10. 最佳String判断是否为空
  11. ftp服务器文件上传代码,Java上传文件FTP服务器代码
  12. 年底绩效考核,领导让我背「C」
  13. ERROR: canceling statement due to conflict with recovery
  14. 毕业了~(2008-06-04 11:22)
  15. SEO采集系统-SEO采集工具自动采集伪原创发布
  16. 10-门面模式Quarkus实现
  17. 多属性决策模型 matlab代码及例子
  18. 新出免费字体——阿里巴巴普惠字体(附安装使用教程)
  19. 倾斜补偿的电子罗盘(3):椭球拟合,磁传感器软磁干扰和硬磁干扰的9参数校准
  20. 独立游戏制作人的罗生门

热门文章

  1. agp计算机组装什么意思,教你怎么组装电脑
  2. 东南大学成贤学院计算机报名,2021上半年江苏东南大学成贤学院计算机等级考试报名通知...
  3. FaceBook到底验证个啥?
  4. c++:std::dec, std::hex, std::oct
  5. 基于STM32+华为云IOT设计智能称重系统
  6. 邮箱大佬告诉你电子邮箱格式如何正确书写
  7. 个人网站如何开通收款功能申请支付接口?
  8. 编译原理-18-语法分析实验代码示例
  9. win10系统进不了服务器失败,快速解决Win10安装失败重启进不了系统的方法
  10. mysql自增长id用完了,怎么办?