算法 图中求最小环路径 最小环个数 最大平均环 求简单无向图中环的个数
来源:互联网 发布:qq网络硬盘在哪里找 编辑:程序博客网 时间:2024/06/03 05:03
最小环问题:求个图中环路径代价最小的回路。
如何求最小环?假如有 路径1->3->2,如果此时已经知道2-1的最短路径就好了。 回想下floyed的更新过程,就会发现更新第k次时,比k小的点之间都是最短距离的(要是点是联通的话)。所以给出解法:第k次更新图时,枚举和k相连的两条边。如 环路代价 = dist[i][k] + dist[k][j] + dist[j][i];
求无向图中最小环的个数,先算出一个最小环代价,把之后算出的环代价与之对比更新就可以了。这个图中是求不同的最小环的个数,所以重边是没有影响的
fzu 2090 http://acm.fzu.edu.cn/problem.php?pid=2090
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 using namespace std; 7 8 #define maxn 108 9 #define INF 1<<2410 int dist[maxn][maxn], g[maxn][maxn];11 int n, m;12 13 void init(){14 for ( int i=1; i<=n; ++i )15 for ( int j=1; j<=n; ++j )16 dist[i][j] = g[i][j] = INF;17 int u, v, w;18 for ( int i=0; i<m; ++i ) {19 scanf("%d%d%d", &u, &v, &w);20 if(dist[u][v] > w) {21 dist[u][v] = dist[v][u] = w;22 g[u][v] = g[v][u] = w;23 }24 }25 };26 27 void solve(){28 int minn = INF, cnt=0;29 for ( int k=1; k<=n; ++k ){30 // 枚举与k相连的两条边,且端点号是小于k的31 for ( int i=1; i<k; ++i ) if(g[i][k]^INF)32 for( int j=i+1; j<k; ++j ) if(dist[i][j]^INF && g[k][j]^INF)33 {34 int tmp = dist[i][j]+g[i][k]+g[k][j];35 if(tmp < minn ) {// 比最小的还小就更新36 minn = tmp; cnt=1;37 }else if(tmp == minn) ++cnt; // 和当前最小的环代价相等38 }39 40 // 更新最短路41 for(int i=1; i<=n; ++i ) if(dist[i][k]^INF)42 for(int j=1; j<=n; ++j ) if(dist[k][j]^INF)43 {44 int tmp= dist[i][k]+dist[k][j];45 if(tmp < dist[i][j]) dist[i][j] = tmp;46 }47 }48 if(cnt > 0) printf("%d %d\n", minn, cnt);49 else puts("-1 -1");50 };51 52 int main(){53 int T; scanf("%d", &T);54 while( T-- ) {55 scanf("%d%d", &n, &m);56 init();57 solve();58 }59 };
求最小环路径,任意一条最小环的路径。
poj 1734 http://poj.org/problem?id=1734
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <vector> 6 #include <algorithm> 7 using namespace std; 8 9 #define maxn 10810 int n, m;11 int dist[maxn][maxn], g[maxn][maxn];12 int pre[maxn][maxn]; // 路径13 #define INF 1<<2414 vector<int > ans;15 16 void init(){17 for(int i=1; i<=n; ++i)18 for(int j=1; j<=n; ++j)19 dist[i][j]=g[i][j]=INF, pre[i][j]=i;20 int u, v, w;21 for(int i=0; i<m; ++i ) {22 scanf("%d%d%d", &u, &v, &w);23 if(w < dist[u][v] ){24 dist[u][v] = dist[v][u] = w;25 g[u][v] = g[v][u] = w;26 }27 }28 };29 30 31 void solve(){32 int minn = INF; ans.clear();33 for(int k=1; k<=n; ++k )34 {35 // 枚举两条边,点号小于k36 for(int i=1; i<k; ++i) if(g[i][k]^INF)37 for(int j=i+1; j<k; ++j) if(g[k][j]^INF && dist[i][j]^INF) {38 int tmp = dist[i][j]+g[i][k]+g[k][j];39 if(tmp < minn) { // 求出路径40 minn = tmp; ans.clear();41 int p = j;42 while(p != i) {43 ans.push_back(p);44 p = pre[i][p];45 }46 ans.push_back(i);47 ans.push_back(k);48 }49 }50 51 for(int i=1; i<=n; ++i ) if(dist[i][k]^INF)52 for(int j=1; j<=n; ++j )if(dist[k][j]^INF) {53 int tmp = dist[i][k]+dist[k][j];54 if(tmp < dist[i][j]) {55 dist[i][j]= tmp;56 pre[i][j] = pre[k][j]; // 从后往前57 }58 }59 }60 61 if(minn ^ INF) {62 //cout<< minn << endl;63 for(int i=0; i<ans.size(); ++i){64 if(i) printf(" "); printf("%d", ans[i]);65 }66 puts("");67 return ;68 }69 puts("No solution.");70 };71 72 int main(){73 while(~scanf("%d%d", &n, &m)){74 init();75 solve();76 }77 };
最大环路问题和最小环路是相同的吧(没遇到过求最大环的);
求最大平均环代价。 知道spfa能够判断环中是否环(正环和负环都是可以的)。开始图中的都是正环(假如有环的话)。对每条边减去一个值,再判断图中是否有正环存在,恰好没有就表明和这个值就是最大的平均环的代价,因为环中x条边都减去y后,恰好会使得整个环不是正环,这个y值就是要求的最大平均环代价了;
poj 2949 http://poj.org/problem?id=2949
求解时只需二分枚举y即可,注意精度;
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 const int maxm = 100005; 8 const int maxn = 27*27; 9 int n, head[maxn], e, N;10 struct Edge{11 int u, v, next; double w;12 Edge(){}13 Edge(int U, int V, int Ne, double W):14 u(U), v(V), next(Ne), w(W){}15 }edge[maxm];16 17 void add(int u, int v, double w){18 edge[e] = Edge(u, v, head[u], w); head[u] = e++;19 }20 21 int mm[30][30];22 23 int get( char x, char y) {24 int i = x-'a', j = y-'a';25 if(mm[i][j] == 0) mm[i][j]=++N;26 return mm[i][j];27 }28 29 double maxLength;30 31 void init(){32 char str[1071];33 e = 0; N = 0; maxLength = 0; //maxLength 最大的边34 memset(head, -1, sizeof head); //开始这里我用的是fill,悲剧的rt了如干次啊35 memset(mm, 0, sizeof mm);36 37 getchar();38 for(int i=0; i<n; ++i ) {39 scanf("%s", str);40 int sz = strlen(str);41 if(sz < 3) continue;42 int u = get(str[0], str[1]);43 int v = get(str[sz-2], str[sz-1]);44 add(u, v, sz); //每个字串见条边就可以了45 if(sz > maxLength) maxLength = sz;46 }47 }48 49 double dist[maxn];50 int cnt[maxn];51 bool vis[maxn];52 int Q[maxn];53 54 bool spfa( double x ) {55 fill(dist+1, dist+1+N, 0);56 fill(cnt+1, cnt+1+N, 0 );57 memset(vis, 0, sizeof vis);58 int l=0, r=0;59 for(int i=1; i<=N; ++i)60 Q[r++] = i, vis[i]=1;61 while(l != r) {62 int u = Q[l++]; if(l == maxn) l=0; vis[u]=0;63 for ( int i=head[u]; ~i; i=edge[i].next){64 int v = edge[i].v; double w = edge[i].w;65 if(dist[u]+w-x > dist[v]){66 dist[v] = dist[u]+w-x;67 if(vis[v] ) continue;68 Q[r++] = v; vis[v]=1;69 if(r == maxn) r=0;70 if(++cnt[v] > N) return 1; // 存在正环71 }72 }73 }74 return 0;75 }76 77 #define eps 1e-478 void solve()79 {80 double l = 0, r = maxLength, mid, ans=-1;81 while(r-l >= eps){// 二分球结果82 mid = (l+r)/2.0;83 if(spfa( mid ) ) {84 ans = mid;85 l = mid;86 }else r = mid;87 }88 if(ans > eps) printf("%.2lf\n", ans);89 else puts("No solution.");90 };91 92 93 int main(){94 while( scanf("%d", &n), n ){95 init();96 solve();97 }98 }
求简单无向图中环的个数?简单无向图即 无自环,无重边的无向图。
这个是NP问题; codeforces 上有一题用的是状态压缩写的。
dp[s][i] s集合里最小的点到其他点的路径数;
dp[s][i] += dp[s^(1<<i)][j](g[j][i]=true)
ans加上可以构成环的路径数.怎么才能构成环呢? 如a->b->.....->c ,如果知道ac是可达的,只要加上a,经过ab...到达c的路径数就可以了。注意a是这个集合里最小的数。而且同一个环会被记录两次,因为2条路径才是一个环。
codeforces 11D http://www.codeforces.com/contest/11/problem/D
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 typedef __int64 ll; 8 #define maxn 20 9 ll dp[1<<maxn][maxn]; // 注意数据10 bool g[maxn][maxn];11 // dp[s][i] s中最小的点到其他点路径数;12 // dp[s][i] += dp[s^i][j](g[i][j] = true )13 14 int main(){15 int n, m;16 while( cin >> n >> m ) {17 memset(g, 0, sizeof g);18 int state = (1<<n);19 for ( int i=0; i<state; ++i)20 for ( int j=0; j<n; ++j )21 dp[i][j] = 0;22 23 for ( int i=0, a, b; i<m; ++i ){24 scanf ("%d%d", &a, &b);25 --a, --b;26 g[a][b] = g[b][a] = true;27 dp[(1<<a)|(1<<b)][a] = dp[(1<<a)|(1<<b)][b] = 1;28 }29 30 ll ans = 0;31 for ( int s=1; s<state; ++s ){32 int i, j, k;33 for ( i=0; i<n && !(s&(1<<i)); ++i );34 for ( j=i+1; j<n; ++j ) if(s&(1<<j) )35 {36 for ( k=i+1; k<n; ++k ) if(s&(1<<k)){37 if(g[k][j] )38 dp[s][j] += dp[s^(1<<j)][k];39 }40 if(g[i][j] && (s^(1<<i)^(1<<j))) // 3个点以上才行41 ans += dp[s][j];42 }43 }44 // 枚举了环的两侧,so。。。45 cout << (ans>>1) << endl;46 }47 };
- 算法 图中求最小环路径 最小环个数 最大平均环 求简单无向图中环的个数
- 算法 图中求最小环路径 最小环个数 最大平均环 求简单无向图中环的个数
- Floyd求最小环并求不同最小环的个数
- 求无向图最小环算法-floyd
- Floyd算法求无向图最小环
- hdu1599求无向图的最小环
- 无向图最小环算法floy
- pku1734求无向图的最小环(Floyd算法扩展)
- 无向图最小环
- 求简单无向图中环的个数
- POJ1734(floyd求最小环的路径)
- hdu1599 Floyd求最大环 最小环
- hdu 1599 (floyd求无向图最小环)
- floyd算法求最小环
- Floyd算法求最小环
- 有向图无向图的最小环。
- 找无向图最小环 floyd算法
- 最小环(有向无向均可)
- BZOJ1001 狼抓兔子 详解 (平面图 spfa)
- Ubuntu 14.04下 MySQL实现单机主从复制
- 《JAVA与模式》之状态模式
- 方立勋_30天掌握JavaWeb_自定义标签
- 3.2产品运营
- 算法 图中求最小环路径 最小环个数 最大平均环 求简单无向图中环的个数
- 用postman调试接口跳过用户登陆的方式
- CSDN-markdown编辑器
- 《剑指Offer》 跳台阶
- long 和 int 的区别
- Python Decorator装饰器
- 树的重心
- Spring中如何装配Bean(一)
- 关于 iOS UITextView 的各种陨石坑 (一) !