【洛谷 P1127】词链
来源:互联网 发布:linux命令创建多层目录 编辑:程序博客网 时间:2024/06/10 02:51
题目描述
如果单词X的末字母与单词Y的首字母相同,则X与Y可以相连成X.Y。(注意:X、Y之间是英文的句号“.”)。例如,单词dog与单词gopher,则dog与gopher可以相连成dog.gopher。
另外还有一些例子:
dog.gopher
gopher.rat
rat.tiger
aloha.aloha
arachnid.dog
连接成的词可以与其他单词相连,组成更长的词链,例如:
aloha.arachnid.dog.gopher.rat.tiger
注意到,“.”两边的字母一定是相同的。
现在给你一些单词,请你找到字典序最小的词链,使得这些单词在词链中出现且仅出现一次。
输入格式:
第一行是一个正整数n(1 ≤ n ≤ 1000),代表单词数量。
接下来共有n行,每行是一个由1到20个小写字母组成的单词输出格式:
只有一行,表示组成字典序最小的词链,若不存在则只输出三个星号“*”。
数据范围:
对于100%的数据,有n≤1000。
补昨天的博客…
首先,这是一道图论题…
这种单词接龙样子的一般都是图论题,相信大家都知(bei)道(keng)了(guo)吧…
如果以单词作为点,能连的单词建边,那好像就是一个裸的哈密顿路了?
不过连边的顺序要注意,先连字典序小的,再连字典序大的,这样能够保证找到的第一条哈密顿路就是答案。
所以要用string类型,先排序,用排名代替单词建图。
然后我就开开心心地敲了一个哈密顿路…
30分…
不光有TLE还有WA…
吓得我扫了好几遍代码,终于发现了华点…
我先把单词从小到大排序,然后对于每一个单词,先连小的再连大的…
也就是:
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(i!=j&&a[i][len[i]-1]==a[j][0]) add(i,j);
我天真地以为这样连就能先访问小的再访问大的…
可是因为head数组指向所连的最后一条边,所以先连的边最后访问啊!
又sb了…不过数据很水还给了三十分…
所以应该把第二层j倒着循环,改完了又交了一遍。
T了两个点..
这道题哈密顿路应该不会错啊…可是怎么优化?
经过冥(fan)思(kan)苦(ti)想(jie)后,我仿若醍醐灌顶…
可以用欧拉路来优化!
如果把二十六个字母作为点,每个单词首尾字母连一条边,那不就是跑欧拉路吗!
不过不能纯跑欧拉路,因为建边的时候不能按照字典序建边(不一定指向a就比指向b小),所以不能保证找到的第一条欧拉路就是答案。
但可以用来查找从那个点开始搜索。
因为如果不存在哈密顿路,那也就不存在欧拉路(这两个路本质上好像没什么区别),如果存在哈密顿路,那么以哈密顿路的开头单词的首字母一定能跑出欧拉路来。
所以我们就可以先判断从哪些字母出发可以跑出欧拉路,再从以这些字母为首的单词开始跑哈密顿路。
虽然理论时间复杂度好像不变,但加了这个优化就跑到12ms了。
代码如下:
#include<cstdio>#include<iostream>#include<algorithm>#include<string>#include<cstring>#include<cstdlib>using namespace std;struct edge{ int to,next;}ed[1000001];int head[1001]={0};string a[1001];int b[30]={0};bool vl[1001]={0};bool vis[1001]={0};int ans[1001]={0};int len[1001];int size=0;int cnt=0,n;void add(int from,int to){ size++; ed[size].to=to; ed[size].next=head[from]; head[from]=size;}void print(){ for(int i=1;i<cnt;i++) { cout<<a[ans[i]]; printf("."); } cout<<a[ans[cnt]]; exit(0);}void dfs(int u){ vl[u]=vis[u]=1; ans[++cnt]=u; for(int i=head[u];i;i=ed[i].next) { int v=ed[i].to; if(!vis[v]) dfs(v); } if(cnt==n) { print(); } vis[u]=0; cnt--;}int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) { cin>>a[i]; } sort(a+1,a+n+1); for(int i=1;i<=n;i++) { len[i]=a[i].size(); } for(int i=1;i<=n;i++) { for(int j=n;j>=1;j--) { if(i!=j&&a[i][len[i]-1]==a[j][0]) { add(i,j); } } } for(int i=1;i<=n;i++) { b[a[i][0]-'a']++; b[a[i][len[i]-1]-'a']--; } int c1=0,c_1=0,s; for(int i=0;i<26;i++) { if(b[i]==1) c1++,s=i; else if(b[i]==-1) c_1++; } if(c1==1&&c_1==1) { for(int i=1;i<=n;i++) { if(a[i][0]-'a'==s) dfs(i); } } else if(c1==0&&c_1==0) { for(int i=1;i<=n;i++) dfs(i); } printf("***"); return 0;}
这个算法好像有个漏洞,就是单纯的sort排序能否保证第一条路径就是答案?
例如abc和abcb,用string比较结果是abc小于abcb,但是如果后面接单词的话就是abc.c…和abcb.b…,显然第二个又更小了…
咸鱼的想法:前面字母都一样最后一个字母不一样几率辣么小忽略不就行辣
也许字典序并不是我理解的那样吧…反正a了就好。
- 【洛谷 P1127】词链
- Vijos P1127 级数求和
- Vijos P1127 级数求和【数列】
- 词链
- 词链
- 【动态规划】【RQ429】词链
- rqnoj-429词链
- 【Trie】【cogs173】词链
- RQNOJ 429 词链
- rqnoj-429词链-字典树
- ACM 173. 词链(单调堆栈)
- 洛谷
- 洛谷
- 洛谷
- RQNOJ LIS专题 201奥运大包围,569Milking Time,429词链
- 洛谷 中位数
- 洛谷p1373
- 洛谷 P1579
- 指定CentOS7虚拟机IP
- linux-基础-进程通讯(一)-管道通信/信号/内存共享
- asp.net c# 异步日志通用类(3)
- 简单文件输出函数
- 二进制及其它进制相互转换(一)
- 【洛谷 P1127】词链
- android 下载进度展示之 progressBar 简单版
- 2014年07月11日
- poj1315 Don\'t Get Rooked
- web前端常用代码集合
- poj1426 Find The Multiple
- poj2251 Dungeon Master
- poj3126 Prime Path
- 为什么ESP8266 TCP透传过程会丢包?8266流控原理以及如何设置