这一道题题面大概是有一个包含a,b,c,d,e,f六种字符的字符串(长度为n),要求它的一个重新排列的字符串,其中有m位可能有对填写的字母的限制。其中保证
要求输出字典序最小的可能解,如果无解输出”Impossible”。
很容易想到的基本思路就是,对于每一位字母,从a到f枚举是否能够填在这一位,如果能够填,就填字母。如果枚举到f,然而仍然没能找到可能的解,则输出无解。这样字典序就会最小。
于是问题的关键便转化为如何判断对于某一位填写某个字母之后,剩下的位能不能全部成功找到匹配,而这个问题又能够转化为图的匹配。
转化为图的匹配之后,问题就能够使用霍尔定理来解决了。
复习霍尔定理:
二部图G中的两部分顶点组成的集合分别为
,G中有一组无公共点的边,一端恰好为组成X的点的充分必要条件是:X中的任意k个点至少与Y中的k个点相邻。(1≤k≤m)。
而在本题中,则是代表在如后面的尚未填充的字母位中的任意k个都能够找到至少k个能够填写的原字符串中尚未使用的字符,就代表后面尚未填写的字符一定有一种方法能够填写。
最终上代码。
// Author : WangZhikun // Date : 2018.07.27 #include <cstdio> #include <vector> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int n,m,msk[100020],p,fn[80] = {0},gn[80] = {0},ccnt[10] = {0}; char s[100020],cm[10],ans[100020]; int main() { ios::sync_with_stdio(false); cin.tie(0); for(int i=0;i<100010;i++)msk[i] = 63; cin>>s; n = (int)strlen(s); cin>>m; for(int i=0;i<m;i++){ cin>>p>>cm; p-=1; msk[p] = 0; for(int i=0;i<strlen(cm);i++) if(cm[i]>='a' && cm[i]<='f') msk[p]+=1<<(cm[i]-'a'); } for(int i=0;i<n;i++){ fn[msk[i]]++; ccnt[s[i]-'a']+=1; } for(int i=0;i<64;i++){ for(int j=0;j<64;j++)if((i&j) == j)gn[i]+=fn[j]; } for(int po=0;po<n;po++){ ans[po] = 'u'; for(int i=0;i<64;i++)if((i&msk[po]) == msk[po])gn[i]-=1; for(int c = 0;c<6;c++){ if((msk[po] & (1<<c)) == 0)continue; ccnt[c]-=1; int co = 1,ccn = 0; for(int i=0;i<64;i++){ ccn = 0; for(int j=0;j<6;j++)if(i&(1<<j))ccn+=ccnt[j]; if(ccn<gn[i]){ co = 0; break; } } if(co){ ans[po] = 'a'+c; break; } else{ ccnt[c]+=1; } } if(ans[po] == 'u'){ cout<<"Impossible"<<endl; return 0; } } cout<<ans<<endl; return 0; }
[latex]
发表回复