loj10082 word rings 字符串接龙的神奇建图+dfs版spfa

对于菜鸡博主而言,此题建图妙啊。。。记下来orz一波。

然后dfs版spfa对于找最短路当然慢得一比,但是找有没有环就快了。。

然后从多点dfs不仅因为图可能不连通,也是因为如果有正环,必然存在某个点,从该点开始到找到正环,

经过的所有点dis都>0。

//可以看成走一条dfs树上的链,在链上的点标记一下,一旦出现回边就找到环了。
int dfs(int k,double x){
    vis[k]=1; //在链上
    repedge(i,k){
    	int v=edge[i].to;
    	if (dis[k]+edge[i].cst-x>dis[v]){
    		dis[v]=dis[k]+edge[i].cst-x;
    		if (vis[v]||dfs(v,x)) return 1; //从k出发有回边或k的子树中有回边
		}
	}
	vis[k]=0; return 0; //这个点出发找不到环,还原成不在链上,方便进入下一条支链
}
int check(double x){
	ms(dis,0,dis); ms(vis,0,vis);
	rep(i,1,n) if (dfs(i,x)) return 1; 
//不需要做一次清零一次,因为如果没有找到,必定都被还原了;
//要从每个点dfs一次,因为图可以是不连通的。
	return 0;
}

总:

#include<bits/stdc++.h>
using namespace std;
#define rep(x,y,z) for (int x=y; x<=z; x++)
#define downrep(x,y,z) for (int x=y; x>=z; x--)
#define ms(x,y,z) memset(x,y,sizeof(z))
#define LL long long
#define repedge(x,y) for (int x=hed[y]; ~x; x=edge[x].nex)
inline int read(){
	int x=0; int w=0; char ch=0;
	while (ch<'0' || ch>'9') w|=ch=='-',ch=getchar();
	while (ch>='0' && ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return w? -x:x;
}
const double eps=1e-4;
const int N=30*30;
const int M=100005;
int n,tot,vis[N],hed[N],nedge,fg[N];
double dis[N];
struct Edge{ int to,nex; double cst; }edge[M<<1];
void addedge(int a,int b,double c){
	edge[nedge].to=b; edge[nedge].nex=hed[a];
	edge[nedge].cst=c; hed[a]=nedge++;
}
int dfs(int k,double x){
    vis[k]=1;
    repedge(i,k){
    	int v=edge[i].to;
    	if (dis[k]+edge[i].cst-x>dis[v]){
    		dis[v]=dis[k]+edge[i].cst-x;
    		if (vis[v]||dfs(v,x)) return 1;
		}
	}
	vis[k]=0; return 0;
}
int check(double x){
	ms(dis,0,dis); ms(vis,0,vis);
	rep(i,1,n) if (dfs(i,x)) return 1;
	return 0;
}
double solve(){
	double l=0; double r=1000;
	while (l+eps<r){
		double mid=((l+r)*0.5);
		if (check(mid)) l=mid;
		else r=mid;
	}
	return l;
}
char s[1005];
int main(){
	for ( ; ; ){
		scanf("%d",&tot); if (!tot) break; n=0; nedge=0; ms(hed,-1,hed); ms(fg,0,fg);
		rep(i,1,tot){ scanf("%s",&s); int m=strlen(s);
		   if (m<1) continue; int x=(s[0]-'a')*26+(s[1]-'a'); int y=(s[m-2]-'a')*26+(s[m-1]-'a');
		   if (!fg[x]) fg[x]=++n; if (!fg[y]) fg[y]=++n; addedge(fg[x],fg[y],m);
		}
		double ans=solve(); 
		if (ans<eps) puts("No solution"); else printf("%0.2f\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/shiveringkonnyaku/article/details/82848059
今日推荐