Description
有一天Mirko 和他忠诚的朋友Slavko 感动非常的无聊。他们无聊的结果就是创造出一个新游戏!在游戏的开始,他们在一个坐标系中画下N 个点。玩家轮流开始他们的回合,并且Mirko 首先开始。他画一条直线,平行坐标系其中一个轴,并且经过N 个点中的一个点。在接下来的步骤中,玩家需要画一条平行坐标系一条轴的直线,并且经过N 个点中被上一步对手画下直线经过的点。每条直线不能重复绘制。不能完成自己一局的玩家为输家。
确定谁有必胜策略。
输入的第一行包含正整数N(1<=N<=10000)。
接下来N行每行包含两个整数X和Y,画下的点的坐标(1<=X,Y<=500)。
Output
输出唯一的一行包含必胜玩家的名字,‘Mirko’或‘Slavko’。
输入1:
3
1 1
1 2
1 3
输入2:
4
1 1
1 2
2 1
2 2
Sample Output
输出1:
Mirko
解释:如果Mirko 画直线y=1,那么Slavko 迫不得已要画x=1,然后Mirko 画直线y=2,这样Slavko 只能重新再画直线x=1,这是不被允许的。
输出2:
Slavko
Data Constraint
40%的数据满足N<=10。
解题思路
可以发现,每相邻两次操作,一个是x轴方向,另一个是y轴方向
于是,可以划分出x方向,y方向的两组点,形成二分图,当有一点(x1,y1)时,把x=x1与y=y1连一条边。
匈牙利算法跑最大匹配,当完全匹配时,后手赢,因为不管增广路如何最后先手会走不了,反之,则先手赢。
Source Code
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int N=10010;
const int M=5100;
int s[M][M];
int cover[N],link[N],tt[N],f[N];
int n,m,t;
int x[N],y[N];
void init()
{
scanf("%d",&n);
m=0; t=0;
memset(tt,0,sizeof(tt));
for (int i=1;i<=n;++i)
{
scanf("%d%d",&x[i],&y[i]);
m=max(m,x[i]);
}
for (int i=1;i<=n;++i)
{
t=max(t,y[i]);
y[i]+=m;
s[x[i]][++s[x[i]][0]]=y[i];
s[y[i]][++s[y[i]][0]]=x[i];
tt[x[i]]=1; tt[y[i]]=1;
}
memset(link,0,sizeof(link));
}
bool dfs(int i)
{
for (int k=1;k<=s[i][0];++k)
if (cover[s[i][k]]==0)
{
int q=link[s[i][k]];
link[s[i][k]]=i;
cover[s[i][k]]=1;
if (dfs(q) || q==0) return true;
link[s[i][k]]=q;
}
return false;
}
int main()
{
freopen("linije.in","r",stdin);
freopen("linije.out","w",stdout);
init();
for (int i=1;i<=m;++i)
{
if (tt[i]==0) continue;
memset(cover,0,sizeof(cover));
dfs(i);
}
memset(f,0,sizeof(f));
for (int i=1;i<=m+t;++i)
if (tt[i]==1 && link[i]!=0) {f[i]=1; f[link[i]]=1;}
for (int i=1;i<=m+t;++i)
if (f[i]==0) {printf("Mirko\n"); return 0;}
printf("Slavko\n");
return 0;
}