首页 > 其他 > 详细

Word rings

时间:2020-07-26 23:30:00      阅读:131      评论:0      收藏:0      [点我收藏+]

Word rings

题目描述

这道题就是想求出所有的环,然后在所有环中比较出环串的平均长度最长的那一个,然后就输出平均长度最长的,如果在一个点当中的样例中没有环的话我们就应该输出“No Sulution.”


- 注意是No Sulution. 有句点,题目的翻译有一点问题在测试中数据有句点,在原文中也有句点


首先我们的思路应该是跑最长路,因为无论我们想求平均长度最长,我们肯定希望每一个都非常长,刚好边权为字符串长度,那么跑一下当正环出来之后就跑不出来了。但是这题数据太大了我们过不了

当我们首先用枚举环来求出答案士失败时那么我们接下来的思路应该是尝试枚举答案,然后求出是否有满足答案的环,但若我们此时枚举的答案为ans,有k个字符串,那么就有了这样一个式子ans∗k=len1+len2+len3+...+lenkans∗k=len1+len2+len3+...+lenk

在我们得到那道这个式子之后,我们对它进行必要的移项

len1−ans+len2−ans+len3−ans+...+lenk−ans=0

所以说我们可以得到对于满足以下式子,也可以判断是否是正环

0≤len1−ans+len2−ans+len3−ans+...+lenk−ans0

那么对于这个ans值,ans值越大,那么存在正环的概率也就越小,当ans值越小时,ans大的情况肯定也会包含在里面,这就保证了单调性,我们在确定这个方法的单调性之后我们就可以直接使用二分答案来做这道题了。

对于最长路的求解我们应该使用Dijkstra对此进行判断正环(因为Dijkstra不能处理负数情况,时间的复杂度比较低),但是我们也可以用SPFA来判正环(我们可以将每一条边的权值乘以负一),然后我们再加一个spfa优化就可以了。

补充

在这里讲一下如何进行缩点,在题目中我们不难发现对于一串字符串来说只有首尾的各两个数字是有用的,其他的字符我们可以忽略不计,但是我们学要用一下哈希来使我们的aa到zz中间的所有的字符不会冲突,(第一位可以乘以26,第二位用1到25表示,那么我们得到的那个数整除26的和然后再+1就代表第一个字符在a到z中的第几个位置,之后我们可以再用那个数模26然后再+1就代表第二个字符在a到z中的第几个位置)这样可以保证不会出现冲突了。

直接把一个字符串当中的首尾各两个字符变为两个点整个字符串的长度为我们的边权建立一条边这样就可以进行建边了,再执行之前的工作就可以work it out(解决)了

好题推荐

(spfa的优化的题目)

这些题可以帮助大家练习好spfa的优化的题目

代码

#include<bits/stdc++.h>
using namespace std;
const int N=100005;
const double eps=1e-6;
int n;
char s[1005];
int ord(char a,char b) {//缩点(避免冲突)
    return (a-a)*26+b-a;
}
int lnk[N],ne[N],la[N],co[N],tot;
double dis[N];
bool vis[N];
void add(int x,int y,int z) {
    ne[++tot]=y;
    co[tot]=z;
    la[tot]=lnk[x];
    lnk[x]=tot;
}
bool dfs(int x,double v) {//dfs版的spfa
    vis[x]=1;
    for(int j=lnk[x]; j; j=la[j]) {
        if(dis[ne[j]]<dis[x]+co[j]-v) {
            dis[ne[j]]=dis[x]+co[j]-v;
            if(vis[ne[j]])return 1;
            else {
                if(dfs(ne[j],v))return 1;
            }
        }
    }
    vis[x]=0;
    return 0;
}
bool check(double mid) {//判断是否是负环
    memset(vis,0,sizeof(vis));
    memset(dis,0,sizeof(dis));
    for(int i=0; i<=5000; ++i)
        if(dfs(i,mid))return 1;
    return 0;
}
int main() {
    while(cin>>n) {
        memset(lnk,0,sizeof(lnk));
        tot=0;
        if(n==0){
            return 0;
        }
        for(int i=1; i<=n; ++i) {
            scanf("%s",s+1);
            int l=strlen(s+1);
            add(ord(s[1],s[2]),ord(s[l-1],s[l]),l);
        }
        double l=0,r=1005;
        while(r-l>eps) {//进行二分答案求解
            double mid=(l+r)/2;
            if(check(mid))l=mid;
            else r=mid;
        }
        if(l==0)cout<<"No solution."<<endl;
        else cout<<l<<endl;
    }
}

 

Word rings

原文:https://www.cnblogs.com/wozuishuaiwozuiniu6/p/13382166.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!