您的位置:首页 > 其它

【JZOJ3852】单词接龙

2017-01-17 21:38 309 查看

Description

Bsny从字典挑出N个单词,并设计了接龙游戏,只要一个单词的最后两个字母和另一个单词的前两个字母相同,那么这两个单词就可以有序的连接起来。

Bsny想要知道在所给的所有单词中能否按照上述方式接龙组成一个单词环(可能是多个),若能,求所有环的环中单词平均长度最大值。

Solution

我们把前两个字符或后两个字符看成点,单词看成边。

设ans为答案,那么∑mi=1aim≥ans

∑mi=1ai≥ans⋅m

∑mi=1ai−ans≥0

然后我们二分答案,把所有边权减去ans,然后在图中找正权环即可。

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define rep(i,x) for(int i=ls[x];i;i=nx[i])
#define N 100010
#define SIZE 7010
#define eps 0.001
using namespace std;
int to
,nx
,ls
,num=0;
double val
;
int c[SIZE],tot=0;
char s[SIZE];
void link(int x,int y,double c)
{
num++;
to[num]=y;
nx[num]=ls[x];
ls[x]=num;
val[num]=c;
}
int g(char a,char b){
return (a-'a')*100+(b-'a');
}
int d
,in
;
double dis
;
bool vis[SIZE],bz[SIZE];
int spfa(int qd,double z)
{
fo(i,0,tot) dis[i]=-2354343435434.00;
memset(vis,0,sizeof(vis));
memset(in,0,sizeof(in));
int l=0,r=1;
d[1]=qd;
vis[qd]=bz[qd]=1;
dis[qd]=0;
while(l<r)
{
l++;
int x=d[l];
rep(i,x)
{
int v=to[i];
if(dis[v]<dis[x]+val[i]-z)
{
dis[v]=dis[x]+val[i]-z;
if(!vis[v])
{
in[v]++;
if(in[v]>tot) return 1;
vis[v]=bz[v]=1;
d[++r]=v;
}
}
}
vis[x]=0;
}
return 0;
}
bool check(double mid)
{
memset(bz,0,sizeof(bz));
fo(i,1,tot)
if(!bz[i])
if(spfa(i,mid)>0) return 1;
return 0;
}
int main()
{
int n;
scanf("%d",&n);
int mx=0;
fo(i,1,n)
{
scanf("%s",s+1);
int l=strlen(s+1);
int t1=g(s[1],s[2]),t2=g(s[l-1],s[l]);
if(!c[t1]) c[t1]=++tot;
if(!c[t2]) c[t2]=++tot;
link(c[t1],c[t2],l*1.0);
mx=max(mx,l);
}
printf("%d\n",check(883.87));
double l=0,r=mx*1.0;
while(l+eps<r)
{
double mid=(l+r)/2;
bool t=check(mid);
if(t) l=mid;
else r=mid;
}
printf("%.2lf",l);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: