题目大意:给n个字符串,字符串表达的是一种特殊的数字,例如说as.asf.wad,就是三位数,从左到右分别为高位到地位。n个字符串按照递增序列给出,递增的比较规则和数字相同。要求求出来这些特殊数字的相对大小,从小到大排序,无法判断大小就按字典序升序排列。
思路:
1.可以想到只有数位相同的比较才是有意义的例如5,24,不能确定5是否大于2。那么就可以想到需要记录当前字符串之前的字符串。
2.二个数位相同的数如果高位不同,那么之后的位数比较就是没有意义的,第一个不同的位置就是有效的相对大小。
3.根据人脑可以比较出这些特殊数位的相对大小,那么代码应该怎么比较?可以想到让低位的数字向高位数字建一条有向边,并且记录入度,使用拓扑排序来输出相对大小,题目要求的字典序可以使用优先队列来实现。
4.如果是数字建图很容易,但是给出的是一堆字符串,那么就可以使用map来标记当前字符串是否出现过,如果没有出现那么就给予一个数字编号。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10;
ll h[N],e[N],ne[N],idx,ind[N];//建图
string sv[N];//用编号找字符串
unordered_map<string,ll> op;//给字符串建立编号
void add(ll a,ll b)
{e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int main()
{ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);ll n;cin>>n;memset(h,-1,sizeof(h));ll cnt=1;vector<string> pre;//之前的字符串for(int i=1;i<=n;i++){vector<string> q;//当前的字符串string s;cin>>s;s=s+'.';//因为末尾需要一个特殊数位是以.结尾的ll wz=0;for(int j=0;j<s.size();j++){string v;if(s[j]=='.'){v=s.substr(j-wz,wz);//从j-wz开始,截取wz个字符wz=0;if(!op[v])//如果没有出现就给予字符串编号{sv[cnt]=v;//编号找字符串op[v]=cnt++;}q.push_back(v);}else wz++;}if(i==1)pre=q;//第一个字符串不能比较else {if(pre.size()==q.size()){for(int j=0;j<q.size();j++){if(pre[j]!=q[j])//第一位不同就是这次比较的有效大小数位{add(op[pre[j]],op[q[j]]);ind[op[q[j]]]++;break;}}}pre=q;}}priority_queue<string,vector<string>,greater<string>> kp;//满足题意的字典序for(auto &[x,y]:op){if(ind[y]==0)kp.push(x);}vector<string> ans;while(kp.size()){string s1=kp.top();kp.pop();ans.push_back(s1);for(ll i=h[op[s1]];~i;i=ne[i]){ll j=e[i];ind[j]--;if(ind[j]==0){kp.push(sv[j]);//编号找字符串}}}for(int i=0;i<ans.size();i++){if(i)cout<<'.';cout<<ans[i];}return 0;
}