#二分,负环#JZOJ 3852 单词接龙 From 2020.01.16【NOIP提高组】模拟A 组

题目

只要一个单词的最后两个字母和另一个单词的前两个字母相同,那么这两个单词就可以有序的连接起来。给出\(n\)个单词组成单词环,求所有环的环中单词平均长度最大值。


分析

二分答案,判断是否存在正环(代码里边权取反求负环),如果存在那么答案不止当前答案


代码

#include <cstdio>
#include <cstring>
#include <queue>
#define rr register
using namespace std;
struct node{int x,y,w,next;}e[100011];
int n,len,k=1,ls[701],cnt,t[701],p[701];
char s[1011]; double dis[701],l,r; bool v[701];
inline bool check(double now){
    rr queue<int>q;
    for (rr int i=1;i<=cnt;++i)
        q.push(i),v[i]=1,t[i]=dis[i]=0;
    while (q.size()){
        rr int x=q.front(); q.pop();
        for (rr int i=ls[x];i;i=e[i].next)
        if (dis[e[i].y]>dis[x]+now-e[i].w){
            dis[e[i].y]=dis[x]+now-e[i].w;
            if (++t[e[i].y]>cnt&&now<e[i].w) return 0;
            if (!v[e[i].y]) v[e[i].y]=1,q.push(e[i].y);
        }
        v[x]=0;
    }
    return 1;
}
inline void add(int x,int y,int w){e[++k]=(node){x,y,w,ls[x]},ls[x]=k;}
signed main(){
    scanf("%d",&n),l=1e12;
    for (rr int i=1;i<=n;++i){
        scanf("%s",s),len=strlen(s),l=l<len?l:len,r=r>len?r:len;
        rr int s1=(s[0]^96)*26+(s[1]^96)-26;
        rr int s2=(s[len-2]^96)*26+(s[len-1]^96)-26;
        if (!p[s1]) p[s1]=++cnt; if (!p[s2]) p[s2]=++cnt;
        add(p[s1],p[s2],len);
    }
    if (check(l)) return !printf("No solution.");
    while (1e-2+l<r){
        rr double mid=(l+r)/2;
        if (check(mid)) r=mid;
            else l=mid;
    }
    return !printf("%lf",l);
}

猜你喜欢

转载自www.cnblogs.com/Spare-No-Effort/p/12311904.html