POJ 2949 Word Rings
题意:给你一些单词,如果一个单词的后两个字母和另外一个单词的前两个字母一样,那么这两个单词就可以连在一起,然后让你求单词成环之后,最大的平均权值。
解法:求平均权值最大的环路? 记得一本书上说过,假如所有的边都在环中,其实就是:E1+E2+E3+E4+....+En = mid*n;转换一下即为:E1-mid+E2-mid+...En-mid = 0;这是权值相等的时候。 要使得mid最大,那么我们可以把E1-mid做为原先图的边。如果有正环存在,说明权值可以继续增大。 二分枚举mid即可。
要用stack来进行入队、出队操作才可以过,要不是会TLE。原因在一篇论文集上有所说明,我认为只需掌握怎么写就行了。
#include <iostream> #include <cstdlib> #include <cstdio> #include <string> #include <cstring> #include <cmath> #include <queue> #include <vector> #include <algorithm> #include <set> #include <map> #include <stack> using namespace std; int k, n, m; const int maxn = 2010; const int maxm = 1010*1010*2; const int INF = 0x3f3f3f3f; double d[maxn]; struct Edge { int u, v; double w; int next; }edge[maxm]; int cnt; int first[maxn]; void read_graph(int u, int v, double w) { edge[cnt].v = v, edge[cnt].w = w; edge[cnt].next = first[u], first[u] = cnt++; } bool inq[maxn]; double L, R; int spfa(double mid) { stack<int> Q; for(int i = 1; i <= k; i++) { d[i] = 0; Q.push(i); inq[i] = 1; } int CNT[maxn] = {0}; while(!Q.empty()) { int x = Q.top(); Q.pop(); inq[x] = 0; for(int e = first[x]; e != -1; e = edge[e].next) { int v = edge[e].v; double w = edge[e].w; if(d[v] < d[x]+w) { d[v] = d[x]+w; if(!inq[v]) { inq[v] = 1; if(++CNT[v] > k) return 1; Q.push(v); } } } } return 0; } void init() { cnt = 0; memset(first, -1, sizeof(first)); } int ord(char x, char y) { return (x-'a')*26+y-'a'+1; } int have_cycle(double mid) { for(int i = 0; i < m; i++) edge[i].w -= mid; int flag = 0; if(spfa(mid)) flag = 1; for(int i = 0; i < m; i++) edge[i].w += mid; return flag; } const double eps = 1e-2; char word[1010]; int vis[3010]; int main() { while(scanf("%d", &m)) { if(!m) break; init(); memset(vis, 0, sizeof(vis)); L = 0, R = 0; k = 0; for(int i = 0; i < m; i++) { scanf("%s", word); int len = strlen(word); int a = ord(word[0], word[1]); int b = ord(word[len-2], word[len-1]); if(!vis[a]) vis[a] = ++k; if(!vis[b]) vis[b] = ++k; R = max(R, len*1.0); read_graph(vis[a], vis[b], len*1.0); } double ans = -1; while(R-L >= eps) { double mid = L+(R-L)/2.0; if(have_cycle(mid)) { ans = mid; L = mid; } else R = mid; } if(ans == -1) printf("No solution.\n"); else printf("%.2f\n", ans); } return 0; }