poj 2983

题意:给你n个串,让你找到一系列串,这些串首尾相连(开头和结尾的两个字母相同),问最大的平均长度是多少

思路:做差分约束做到的这道题,但是很明显不是差分约束。。看起来有点像01分数规划=。=,事实证明还是有点关系的。。

///渣渣题解。。不知道的最好出门左转=。=

这道题要求一些字符串长度和的最大值,二分这个最大值,就得到一个不等式,就是 选取的字符串的长度和/n > mid,如果存在这样的串l = mid,反之。。,就这样二分,满足精度 跳出输出解,现在任务就是判断是否存在这样的环,把这个不等式变形之后:长度和>mid * n,接着变形,得到:长度减去mid的和>0,这样把边权换为减去mid的之后,判断是否有正环就好了。。

原来判负环一直都是用spfa判断进队次数,这次学了个dfs版的spfa,传说中比那个快=。=

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#include<vector>
#include<queue>
const int maxn = 1000;
const double eps = 1e-6;
int n;
struct Side{
    int v,next;
    double w;
}side[maxn*maxn];
int node[maxn],top;
void add_side(int u,int v,double w){
    side[top] = (Side){v,node[u],w};
    node[u] = top++;
}
int mm[maxn][maxn];
bool have[maxn];
double dis[maxn];
bool is[maxn];
int flag;///fu huan
void dfs(int s,double mid){
    is[s] = 1;
    for(int i = node[s];i != -1;i = side[i].next){
        int v = side[i].v;
        if(dis[v] < dis[s] + side[i].w - mid){
            dis[v] = dis[s] + side[i].w -mid;
            if(is[v]){
                flag = 1;
                return;
            }
            dfs(v,mid);
            if(flag)return;
        }
    }
    is[s] = 0;
}
bool judge(double mid){
    for(int i = 0;i < maxn;i ++){
        dis[i] = -10000;
        is[i] = false;
    }
    flag = 0;
    for(int i = 1;i < maxn;i ++){
        if(have[i]){
            dfs(i,mid);
            if(flag)return true;
        }
    }
    return false;
}
int main(){
    //freopen("in.txt","r",stdin);
    while(~scanf("%d",&n),n){
        memset(node,-1,sizeof(node));
        memset(mm,0,sizeof(mm));
        memset(have,0,sizeof(have));
        top = 0;
        char s[1100];
        double l = 0,r = 0,mid;
        for(int i = 1;i <= n;i ++){
            scanf("%s",s);
            int l = strlen(s);
            r = max(r,(double)l);
            int tail,head;
            if(l == 1)head = tail = s[0] - 'a';
            else {
                head = (s[0] - 'a')*30 + s[1] - 'a' + 1;
                tail = (s[l-2] - 'a')*30 + s[l-1] - 'a' + 1;
            }
            mm[head][tail] = max(l,mm[head][tail]);
            have[head] = have[tail] = 1;
        }
        for(int i = 0;i < maxn;i ++){
            if(have[i] == 0)continue;
            for(int j = 0;j < maxn;j ++){
                if(have[j] == 0||mm[i][j] == 0)continue;
                add_side(i,j,mm[i][j] * 1.0);
                //cout<<i<<' '<<j<<' '<<mm[i][j]<<endl;
            }
        }
        while(r - l > eps){
            mid = (l + r)/2.0;//cout<<mid<<endl;
            if(judge(mid))l = mid;
            else r = mid;
        }
        if(mid < 1.0)printf("No solution.\n");
        else printf("%.2f\n",mid);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值