【JZOJ3852】单词接龙

Description

Bsny从字典挑出N个单词,并设计了接龙游戏,只要一个单词的最后两个字母和另一个单词的前两个字母相同,那么这两个单词就可以有序的连接起来。
Bsny想要知道在所给的所有单词中能否按照上述方式接龙组成一个单词环(可能是多个),若能,求所有环的环中单词平均长度最大值。

Solution

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

ans 为答案,那么 mi=1aimans
mi=1aiansm
mi=1aians0

然后我们二分答案,把所有边权减去 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[N],nx[N],ls[N],num=0;
double val[N];
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[N],in[N];
double dis[N];
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);
}
posted @ 2017-01-17 21:38  sadstone  阅读(55)  评论(0编辑  收藏  举报