poj2949 Word Rings(图论/spfa判正环 最大平均环)

题目

n(n<=1e5)个纯小写字母组成的单词,第i个单词长为|si|(|si|<=1e3)

你可以取一个或一些单词,使得第一个单词的末两位与第二个单词的首两位相同,

第二与第三,……,最后一个的末两位与第一个的首两位相同

每个单词只能用一次,假设你取了k个单词,单词总长是len,输出最大化的len/k的值

题解

单纯想总结一下,最大平均环问题

将每个单词最开始的两个字母和最后的两个字母分别抽象成两个点,

你需要找到一个环,使得环的平均值最大,

则二分最大的x,使得每条边都减去这个值x后,仍然存在正环,则x就是答案

代码

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
#define fi first
#define se second
typedef pair<int,int> P;
const int INF=0x3f3f3f3f;
const int N=26*26,M=1e3+10;
int m,u,v;
char s[M];
int cnt[N];
double dis[N];
vector<P>E[N];
bool vis[N];
void add(int u,int v,int w){
	E[u].push_back(P(v,w));
}
bool spfa(double x)//最长路 {
	memset(vis,0,sizeof vis);
	memset(cnt,0,sizeof cnt);
	memset(dis,0,sizeof dis);
	queue<int>q;
	for(int i=0;i<N;++i){//类似多源bfs 建一个超级源点加进去 
		vis[i]=cnt[i]=1;
		q.push(i);
	} 
	while(!q.empty()){
		int u=q.front();
		q.pop();
		vis[u]=0;
		for(int i=0;i<E[u].size();++i){
			int v=E[u][i].fi,w=E[u][i].se;
			if(dis[v]<dis[u]+w-x){
				dis[v]=dis[u]+w-x;
				cnt[v]=cnt[u]+1;
				if(cnt[v]>N)return 1;
				if(!vis[v]){
					q.push(v);
					vis[v]=1;
				}
			}
		}
	}
	return 0; 
}
int f(char x,char y){
	int a=x-'a',b=y-'a';
	return a*26+b;
}
int main(){
	while(~scanf("%d",&m)&&m){
		for(int i=0;i<N;++i){
			E[i].clear();
		}
		double l=0,r=0,mid;
		for(int i=1;i<=m;++i){
			scanf("%s",s);
			int len=strlen(s);
			if(len<2)continue;
			r=max(r,(double)len);
			u=f(s[0],s[1]);
			v=f(s[len-2],s[len-1]);
			//printf("u:%d v:%d len:%d\n",u,v,len);
			add(u,v,len);
		}
		for(int i=0;i<30;++i){
			mid=(l+r)/2;
			if(spfa(mid))l=mid;
			else r=mid;
		}
		if(spfa(l))printf("%.2lf\n",l);
		else puts("No solution.");
 	} 
	return 0;
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小衣同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值