题目:

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=;
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=;i<=m;i++)
{
if(ma[x][i]==''&&!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=;i<=n;i++)
scanf("%s",ma[i]+);
for(int i=n+;i<=m;i++)
for(int j=;j<=m;j++)
ma[i][j]=''; int temp=;
for(int i=;i<=n;i++)
{
memset(visit,false,sizeof(visit));
if(find(i)) temp++;
}
if(temp!=n)
{ for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
cout<<"";
cout<<endl;
}
return ;
}
else
{
int k=n+;
for(int i=;i<=m;i++)
{
if(!belon[i])
belon[i]=k++;
}
}
for(int i=;i<=m;i++)
for(int j=;j<=m;j++)
if(ma[i][j]=='')
{
if(belon[j]==i) comb(i,j+m);
else comb(j+m,i);
}
for(int i=;i<=m*;i++)
if(!dfs[i]) tarjian(i);
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
if(ma[i][j]==''&&(belon[j]==i||id[i]==id[j+m]))
cout<<"";
else cout<<"";
}
cout<<endl;
}
return ;
}
 

北京集训TEST12——PA( Mortal Kombat)的更多相关文章

  1. 北京集训TEST13——PA(第k小数)

    题目: Description [问题描述] 从n个数中选若干(至少1)个数求和,求所有方案中第k小的和(和相同但取法不同的视为不同方案).[输入格式]    第一行输入2个正整数n,k.    第二 ...

  2. 北京集训TEST13——PA(Goodness)

    题目: Description 桌面上放有 n 张卡牌.对于每张卡牌,一面是绿色的,另一面是红色的.卡牌的每一面都标有一个整数.对于卡牌a和卡牌b,卡牌a对卡牌b的好感度为卡牌a绿色面的数与卡牌b红色 ...

  3. 【北京集训D2T3】tvt

    [北京集训D2T3]tvt \(n,q \le 1e9\) 题目分析: 首先需要对两条路径求交,对给出的四个点的6个lca进行分类讨论.易于发现路径的交就是这六个lca里面最深的两个所形成的链. 然后 ...

  4. (2016北京集训十)【xsy1528】azelso - 概率期望dp

    北京集训的题都是好题啊~~(于是我爆0了) 注意到一个重要的性质就是期望是线性的,也就是说每一段的期望步数可以直接加起来,那么dp求出每一段的期望就行了... 设$f_i$表示从$i$出发不回到$i$ ...

  5. 【2017 北京集训 String 改编版】子串

    题意 你有一个字符串,你需要支持两种操作: 1:在字符串的末尾插入一个字符 \(c\) 2:询问当前字符串的 \([l,r]\) 子串中的不同子串个数 为了加大难度,操作会被加密(强制在线). \(n ...

  6. 【2016北京集训测试赛(十)】 Azelso (期望DP)

    Time Limit: 1000 ms   Memory Limit: 256 MB Description 题解 状态表示: 这题的状态表示有点难想...... 设$f_i$表示第$i$个事件经过之 ...

  7. 【2016北京集训测试赛(二)】 thr (树形DP)

    Description 题解 (这可是一道很早就碰到的练习题然后我不会做不想做,没想到在Contest碰到欲哭无泪......) 题目大意是寻找三点对的个数,使得其中的三个点两两距离都为d. 问题在于 ...

  8. 【2016北京集训测试赛(八)】 crash的数列 (思考题)

    Description 题解 题目说这是一个具有神奇特性的数列!这句话是非常有用的因为我们发现,如果套着这个数列的定义再从原数列引出一个新数列,它居然还是一样的...... 于是我们就想到了能不能用多 ...

  9. 【2016北京集训测试赛(十六)】 River (最大流)

    Description  Special Judge Hint 注意是全程不能经过两个相同的景点,并且一天的开始和结束不能用同样的交通方式. 题解 题目大意:给定两组点,每组有$n$个点,有若干条跨组 ...

随机推荐

  1. 2018.4.9 Ubuntu install kreogist-mu

    先下载kreogist m文件 然后在下载哪里右键点击打开终端 输入sudo dpkg -i + 文件名 输入密码 下一步会显示 未安装未安装软件包 libmpv1. jiexialai要处理 sud ...

  2. Cross-Entropy Loss 与Accuracy的数值关系(很重要,很好的博客)

    http://www.cnblogs.com/dengdan890730/p/6132937.html

  3. 安装IAR ewarm

    一  安装准备 (ST方案) 1 嵌入式集成开发环境IAR ewarm 5.41 2 J-Link4.20 3 emberznet-4.3.0协议栈安装包 option1:tools - stm32软 ...

  4. Bootstrap历练实例:动画的进度条

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  5. ios 设计模式总结

    设计模式:备注:消息传递模型(Message Passing)是Objective-C语言的核心机制.在Objective-C中,没有方法调用这种说法,只有消息传递.在C++或Java中调用某个类的方 ...

  6. 【上下界网络流 二分】bzoj2406: 矩阵

    感觉考试碰到上下界网络流也还是写不来啊 Description Input 第一行两个数n.m,表示矩阵的大小. 接下来n行,每行m列,描述矩阵A. 最后一行两个数L,R. Output 第一行,输出 ...

  7. 【windows】win7 sp1 系统语言中英文切换

    注:Windows 7 Ultimate and Windows 7 Enterprise (旗舰版和企业版) 可以直接在控制面板/地区和语言中修改显示语言,其他系统不行 进入网站下载相关的MUI包安 ...

  8. day14-推导式和生成器表达式

    1.推导式规则 [每一个元素或者是和元素相关的操作 for 元素 in 可迭代数据类型] ----------遍历之后挨个处理[满足条件的元素相关的操作 for 元素 in 可迭代数据类型 if 元素 ...

  9. 02 Django模型

    ORM 的作用 ORM 作用示意图 ORM 框架的功能 建立模型类和表之间的对应关系,允许通过面向对象的方式来操作数据库 根据设计的模型类生成数据库中的表格. 通过方便的配置就可以进行数据库的切换 数 ...

  10. 使用TensorFlow的卷积神经网络识别手写数字(1)-预处理篇

    功能: 将文件夹下的20*20像素黑白图片,根据重心位置绘制到28*28图片上,然后保存.经过预处理的图片有利于数字的准确识别.参见MNIST对图片的要求. 此处可下载已处理好的图片: https:/ ...