Codeforces Round #403 B. Innokenty and a Football League(二分图匹配)

65 篇文章 0 订阅
8 篇文章 0 订阅

Innokenty is a president of a new football league in Byteland. The first task he should do is to assign short names to all clubs to be shown on TV next to the score. Of course, the short names should be distinct, and Innokenty wants that all short names consist ofthree letters.

Each club's full name consist of two words: the team's name and the hometown's name, for example, "DINAMO BYTECITY". Innokenty doesn't want to assign strange short names, so he wants to choose such short names for each club that:

  1. the short name is the same as three first letters of the team's name, for example, for the mentioned club it is "DIN",
  2. or, the first two letters of the short name should be the same as the first two letters of the team's name, while the third letter is the same as the first letter in the hometown's name. For the mentioned club it is "DIB".

Apart from this, there is a rule that if for some club x the second option of short name is chosen, then there should be no club, for which the first option is chosen which is the same as the first option for the club x. For example, if the above mentioned club has short name "DIB", then no club for which the first option is chosen can have short name equal to "DIN". However, it is possible that some club have short name "DIN", where "DI" are the first two letters of the team's name, and "N" is the first letter of hometown's name. Of course, no two teams can have the same short name.

Help Innokenty to choose a short name for each of the teams. If this is impossible, report that. If there are multiple answer, any of them will suit Innokenty. If for some team the two options of short name are equal, then Innokenty will formally think that only one of these options is chosen.

Input

The first line contains a single integer n (1 ≤ n ≤ 1000) — the number of clubs in the league.

Each of the next n lines contains two words — the team's name and the hometown's name for some club. Both team's name and hometown's name consist of uppercase English letters and have length at least 3 and at most 20.

Output

It it is not possible to choose short names and satisfy all constraints, print a single line "NO".

Otherwise, in the first line print "YES". Then print n lines, in each line print the chosen short name for the corresponding club. Print the clubs in the same order as they appeared in input.

If there are multiple answers, print any of them.

Examples
input
2
DINAMO BYTECITY
FOOTBALL MOSCOW
output
YES
DIN
FOO
input
2
DINAMO BYTECITY
DINAMO BITECITY
output
NO
input
3
PLAYFOOTBALL MOSCOW
PLAYVOLLEYBALL SPB
GOGO TECHNOCUP
output
YES
PLM
PLS
GOG
input
3
ABC DEF
ABC EFG
ABD OOO
output
YES
ABD
ABE

ABO

题意:给你n个字符串,要求给他们编码,每个字符串由两个分开的单词组成,现在有两种编码规则:

1.取第一个单词的前三个字母。

2.取第一个单词的前两个和第二个单词的第一个字母.

然后有一个附加规则,如果一个单词用了第二种命名法,那么其他字符串的第一种命名法若和这个单词的第一种命名法冲突,那么这个字符串就只能采用第二种命名法。

分析:把所有单词按照第一种命名法分类,如果某个缩写多于1个字符串那么这些字符串都必须采用第二种命名法,我们把它们和第二种命名法的缩写连一条边;然后剩下的字符串可以采用两种命名法,我们就分别连一条边,然后跑二分图匹配就可以了。

#include <bits/stdc++.h>
#define MOD 1000000007
#define N 1005
#define XX (names[num][0].substr(0,3))
#define xx (names[num][0].substr(0,2) + names[num][1].substr(0,1))
using namespace std;
string names[2005][2],s[2005];
typedef vector<int> vec;
map<string,vec> f;
map<string,int> Gf;
int n,cnt,Fh[2005],F[2005],G[2005][2005];
bool vis[2005];
void GG()
{
	cout<<"NO"<<endl;
	exit(0);
}
bool Find(int u)
{
	if(vis[u]) return false;
	vis[u] = true;
	for(int i = 1;i <= cnt;i++)
	 if(G[u][i])
	  if(!F[i] || Find(F[i])) 
	  {
	  	 F[i] = u;
	  	 Fh[u] = i;
	  	 return true;
	  }
	return false;
}
int main()
{
	cin.sync_with_stdio(false);
	cin>>n;
	for(int i = 1;i <= n;i++)
	{
		cin>>names[i][0]>>names[i][1];
		int num = i;
		f[XX].push_back(i);
		if(!Gf[xx]) 
		{
			Gf[xx] = ++cnt;
			s[cnt] = xx;
		}
		if(!Gf[XX]) 
		{
			Gf[XX] = ++cnt;
			s[cnt] = XX;
		}
		G[num][Gf[xx]]++;
		G[num][Gf[XX]]++;
	}
	for(auto it : f)
	{
		if(it.second.size() != 1)
		{
			for(auto it2 : it.second)
			{
				int num = it2;
				G[num][Gf[XX]]--;
			} 
		} 
	}
	for(int i = 1;i <= n;i++)
	{
		memset(vis,0,sizeof(vis));
		if(!Find(i)) GG();
	}
	cout<<"YES"<<endl;
	for(int i = 1;i <= n;i++) cout<<s[Fh[i]]<<endl;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值