1.题目描述:
某人需要给若干球队选择队名缩写。已知每个球队的名字必然是<team name><hometown neme>的形式。取队名缩写的规则是固定的,只有两种:选择 team name 的前三个字母作为队名缩写或选择 team name 的前两个字母与 hometown name 的首字母组成队名缩写。每个队的队名缩写都可以从两种中任选一种,问能够使得每个队最终的队名缩写均不同。如果 x 的第一类队名缩写为 x.fi,第二类队名缩写为 x.se,并且x.fi== y.fi,若 x 选择了 x.se作为最终的队名缩写,并且如果 x 的第一类队名缩写为 x.fi,第二类队名缩写为 x.se,那么其他队伍均不能以 y.fi 作为最终的队名缩写。如果是 y.se==x.fi的话,则不触发这一禁制规则。
3.解题思路:
注意红色字,虽然不触发禁制,但是如果按照这个规则,可能出现最终队名相同的,所以还需要处理,比赛时候我就是因为没认真读题一直Wrong answer on test 16
好,言归正传,对于每个队伍,如果选择第二个名称,肯定是会导致它的第一个名称以后都不能使用,那么我们肯定希望尽可能少的出现这种情况,因此先对所有可以的队伍贪心地选取第一个名称选择,如果出现矛盾,这些人必须全换成第二选择。如果新的第二选择和另一个人的第一选择冲突的话那个人必须也换成第二选择,如果那个人也是第二选择那就无解了。 实现就是通过的dfs,没想到15MS这么效率orz
貌似网上题解还有个2-SAT版本,具体实现以后学了再说ORZ
4.AC代码:
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define maxn 100100
#define N 1111
#define eps 1e-6
#define pi acos(-1.0)
#define e exp(1.0)
using namespace std;
const int mod = 1e9 + 7;
typedef long long ll;
typedef unsigned long long ull;
map<string, int> mp;
string fst[N], snd[N], str1, str2;
int ans[N], flag;
void dfs(int id)
{
if (!mp.count(snd[id]))
mp[snd[id]] = id;
else
{
int pos = mp[snd[id]];
if (pos == -1)
mp[snd[id]] = id;
else if (ans[pos] == 2)
flag = 0;
else
{
ans[pos] = 2;
dfs(pos);
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
long _begin_time = clock();
#endif
int n;
while (~scanf("%d", &n))
{
mp.clear();
for (int i = 1; i <= n; i++)
{
cin >> str1 >> str2;
fst[i] = str1.substr(0, 3);
snd[i] = str1.substr(0, 2) + str2[0];
}
flag = 1;
for (int i = 1; i <= n && flag; i++)
{
if (!mp.count(fst[i]))
{
mp[fst[i]] = i;
ans[i] = 1;
}
else
{
ans[i] = 2;
dfs(i);
int pos = mp[fst[i]];
if (pos != -1 && ans[pos] == 1)
{
mp[fst[i]] = -1;
ans[pos] = 2;
dfs(pos);
}
}
}
if (flag)
{
puts("YES");
for (int i = 1; i <= n; i++)
if (ans[i] == 1)
cout << fst[i] << endl;
else
cout << snd[i] << endl;
}
else
puts("NO");
}
#ifndef ONLINE_JUDGE
long _end_time = clock();
printf("time = %ld ms.", _end_time - _begin_time);
#endif
return 0;
}