pku2949——分数规划/图论

题目大意:给定一堆字符串,如果第一个字符串的后两个字母和第二个字符串的前两个字母相同,那么可以把他们俩接起来,求平均长度最大的一个环。

看到题目第一反映就是——这是个图论问题。建图也比较好想一点,做过一些欧拉回路问题的同学肯定都会。关键是求最大平均值,需要利用分数规划。

关于分数规划的介绍请看2007年胡伯涛的OI论文(1.6小节)。

在这个问题里面我们需要最大化目标函数 Max{r | r = sigma(w[i])/len}(len为环的长度,w[i]为边权),我们构造函数g(r) = Max{sigma(w[i])-r*|w|} = Max{w[1]-r+w[2]-r+...+w[len]-r}。也就是说计算g(r)等价于:先将所有的边权减去r,然后在图中找一个最大长度的环。我们并不需要知道g(r)的准确值,只需要知道它与0的大小关系。假设g(r)大于0,则图中一定存在正环~否则的话g(r)<=0。根据g(r)关于r的单调性(随r的增加递减),可以二分r来求零点。

这个题我不知道提交了多少次。。。。悲剧啊,最多有26*26+26个点,我写了个26*26,忘记加26了。。。。我怀疑我今晚26了。。。

View Code
#include <iostream>
#include
<cstdio>
#include
<cstring>
usingnamespace std;

constint N =210000;
constint M =1010;
constdouble eps = 1e-2;
constdouble inf = 1e9;

int n, m, tot, h[M], queue[N], v[N], nxt[N];
double w[N], tmp[N], dis[M];
char str[M];
bool visit[M];

void add(int a, int b, double c)
{
v[tot]
= b;
tmp[tot]
= c;
nxt[tot]
= h[a];
h[a]
= tot++;
}

bool spfa(int u)
{
int i;
bool flag =false;
visit[u]
=true;
for(i = h[u]; i !=-1; i = nxt[i])
{
if(dis[v[i]] < dis[u]+w[i])
{
dis[v[i]]
= dis[u] + w[i];
if(!visit[v[i]]) flag = spfa(v[i]);
else flag =true;
if(flag) returntrue;
}
}
visit[u]
=false;
returnfalse;
}

bool check()
{
int i, j;
for(i =1; i <= n; i++)
{
memset(visit,
false, sizeof(visit));
for(j =1; j <= n; j++) dis[j] =0.0;
if(spfa(i)) returntrue;
}
returnfalse;
}

int main()
{
int i, len, u, v;
double l, r, mid;
while(scanf("%d", &m) != EOF)
{
if(m ==0) break;
memset(h,
-1, sizeof(h));
tot
=0;
r
=0.0;
for(i =0; i < m; i++)
{
scanf(
" %s", str);
len
= strlen(str);
r
= max(r, (double)len);
u
= (str[0]-'a'+1)*26+str[1]-'a'+1;
v
= (str[len-2]-'a'+1)*26+str[len-1]-'a'+1;
add(u, v, (
double)len);
}
n
=26*26+26;
l
=0.0;
r
+=1.0;
while(r-l >= eps)
{
mid
= (l+r) /2;
for(i =0; i < tot; i++) w[i] = tmp[i]-mid;
if(check())
l
= mid;
else r = mid;
}
if(l <0.01) printf("No solution.\n");
else printf("%.2f\n", l);
}
return0;
}

  

 

 

 

posted on 2011-08-14 21:11  Moon_1st  阅读(307)  评论(0编辑  收藏  举报

导航