洛谷SP2885 WORDRING - Word Rings(0/1分数规划)(SPFA)

版权声明:本文为博主原创文章,未经博主允许不得转载,除非先点了赞。 https://blog.csdn.net/A_Bright_CH/article/details/83421304

题目

洛谷SP2885 WORDRING - Word Rings

题解

0/1分数规划+spfa判正环
先套0/1分数规划的公式:

L=\frac{\sum len[i]*x[i]}{\sum 1*x[i]}

再一变

\sum( len[i] - L)*x[i]

接下来就是一个判正环的问题了。如果有正环则上式>=0,即L有更大取值;否则L无法达到这么优。

提一下建边,真的要做一个什么KMP,AC/后缀自动机,还是马拉车?都是乱来!这样想,它说的是后两个字符,所以不妨直接用两个字符表示点的编号,这样只要给相同字符用一个点,顺便就完成了匹配任务。

总结

我要总结的不是0/1分数规划,是想说一下dfs实现的spfa判正(负)环速率要比bfs实现的spfa要快的多得多。建议以后判环都用dfs来实现spfa。这里的spfa作为一个我dfs实现的spfa的模版。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const double eps=1e-4;
const int inf=0x80808080;
const int maxt=26*26,maxn=100010,maxl=1010;

int n;
int ma[maxt+10][maxt+10];
char s[maxl];

struct E{int y,c,next;}e[maxn*2];int len=0,last[maxt+10];
void ins(int x,int y,int c)
{
    e[++len]=(E){y,c,last[x]};last[x]=len;
}

double d[maxt+10];bool vis[maxt+10];
bool spfa(int x,double L)
{
    vis[x]=true;
    for(int k=last[x];k;k=e[k].next)
    {
        int y=e[k].y;
        if(d[y]<d[x]+e[k].c-L)
        {
            d[y]=d[x]+e[k].c-L;
            if(vis[y] || spfa(y,L))
            {
                vis[x]=false;
                return true;
            }
        }
    }
    vis[x]=false;
    return false;
}

bool check(double L)
{
    memset(d,0,sizeof(d));
    for(int i=1;i<=maxt;i++)
        if(spfa(i,L)) return true;
    return false;
}

int main()
{
    while(scanf("%d",&n),n)
    {
        int sum=0;
        len=0;memset(last,0,sizeof(last));
        memset(ma,0x80,sizeof(ma));
        for(int i=1;i<=n;i++)
        {
            scanf("%s",s+1);
            int l=strlen(s+1);
            if(l<2) continue;sum+=l;
            s[1]-='a';s[2]-='a';s[l-1]-='a';s[l]-='a';
            int x=s[1]*26+s[2]+1,y=s[l-1]*26+s[l]+1;
            ma[x][y]=max(ma[x][y],l);
        }
        for(int i=1;i<=maxt;i++)
            for(int j=1;j<=maxt;j++)
                if(ma[i][j]!=inf) ins(i,j,ma[i][j]);
        
        double l=0,r=sum,ans=-1;
        while(l-r<=eps)//(l<r)
        {
            double mid=(l+r)/2;
            if(check(mid)) ans=mid,l=mid+eps;
            else r=mid-eps;
        }
        if(ans==-1) puts("No solution.");
        else printf("%.2lf\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/A_Bright_CH/article/details/83421304
今日推荐