hdu4725The Shortest Path in Nya Graph(拆点 + 最短路dijkstra | SPFA)

时间:2023-02-02 20:54:50

poj1637Sightseeing tour(混合图欧拉回路)

分类: 网络流 欧拉回路 图论 294人阅读 评论(0)收藏举报 图论网络流欧拉回路

题目请戳这里

题目大意:求混合图欧拉回路。

题目分析:最大流。竟然用网络流求混合图的欧拉回路,涨姿势了啊啊。。

其实仔细一想也是那么回事。欧拉回路是遍历所有边一次又回到起点的回路。双向图只要每个点度数为偶数即可,有向图要保证所有点入度等于出度。求路径的话,dfs即可。

混合图的话,就比较复杂。首先将有向边定向,求出所有点的入度和出度,如果某个点入度和出度之差为奇数,则一定不存在欧拉回路,因为对于混合图,无向边可以任意指定方向,但是无论指定哪个方向,如果取反向的话,只会影响端点的一个出度和一个入度,所以无论无向边如何定向,是不影响节点入度和出度之差的奇偶性的。无向边定向后转化成一张有向图,那么所有的顶点就分成3类:

1:入度= 出度的点,已经是平衡点了,不管;

2:入度>出度的点,向汇点建一条边,边权为(入度- 出度)/2;

3:入度<出度的点,源点与之建一条边,边权为(出度- 入度)/2;

这样跑一遍最大流,看是否为满流。如果是满流,就存在欧拉回路。

因为如果跑出来一个满流,那么对于每个入度>出度的点,都有x条边进来,那么这x条边反向,那么该节点入度=出度,平衡了,对于每个出度>入度的点也是同理。对于出度=入度的点,因为建图的时候没有管他们,也就是说他们本来就是平衡点,所以源点和汇点与之没有直接边,但并不代表这些点就不在图中,因为非平衡点会与之有边相连。如果要求一条具体的欧拉回路的话,只要看具体的网络流,对于流量为1的边,取反便是欧拉回路中一条边了。所谓取反只是对无向边而言的,说明一开始对无向边定向定反了。

详情请见代码:

[cpp] view plaincopyprint?
  1. #include <iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #include<cmath>
  6. using namespace std;
  7. const int N = 205;
  8. const int M = 40000;
  9. const int inf = 0x3f3f3f3f;
  10. int n,m,num,sum;
  11. int head[N],sta[N],que[N],cnt[N],dis[N],rpath[N];
  12. int in[N],out[N];
  13. struct node
  14. {
  15. int to,c,next,pre;
  16. }arc[M];
  17. void build(int s,int e,int cap)
  18. {
  19. arc[num].to = e;
  20. arc[num].c = cap;
  21. arc[num].next = head[s];
  22. head[s] = num ++;
  23. arc[num - 1].pre = num;
  24. arc[num].pre = num - 1;
  25. arc[num].to = s;
  26. arc[num].c = 0;
  27. arc[num].next = head[e];
  28. head[e] = num ++;
  29. }
  30. void init()
  31. {
  32. int i,a,b,d;
  33. scanf("%d%d",&n,&m);
  34. for(i = 1;i <= n;i ++)
  35. in[i] = out[i] = 0;
  36. memset(head,-1,sizeof(head));
  37. num = 0;
  38. while(m --)
  39. {
  40. scanf("%d%d%d",&a,&b,&d);
  41. if(d == 0)
  42. build(a,b,1);
  43. out[a] ++;
  44. in[b] ++;
  45. }
  46. }
  47. void re_Bfs()
  48. {
  49. int i,front,rear;
  50. for(i = 0;i <= n + 1;i ++)
  51. {
  52. dis[i] = n + 2;
  53. cnt[i] = 0;
  54. }
  55. dis[n + 1] = 0;
  56. cnt[0] = 1;
  57. front = rear = 0;
  58. que[rear ++] = n + 1;
  59. while(front != rear)
  60. {
  61. int u = que[front ++];
  62. for(i = head[u];i != -1;i = arc[i].next)
  63. {
  64. if(arc[arc[i].pre].c == 0 || dis[arc[i].to] < n + 2)
  65. continue;
  66. dis[arc[i].to] = dis[u] + 1;
  67. cnt[dis[arc[i].to]] ++;
  68. que[rear ++] = arc[i].to;
  69. }
  70. }
  71. }
  72. int ISAP()
  73. {
  74. re_Bfs();
  75. int i,u,maxflow = 0;
  76. for(i = 0;i <= n + 1;i ++)
  77. sta[i] = head[i];
  78. u = 0;
  79. while(dis[0] < n + 2)
  80. {
  81. if(u == n + 1)
  82. {
  83. int curflow = inf;
  84. for(i = 0;i != n + 1;i = arc[sta[i]].to)
  85. curflow = min(curflow,arc[sta[i]].c);
  86. for(i = 0;i != n + 1;i = arc[sta[i]].to)
  87. {
  88. arc[sta[i]].c -= curflow;
  89. arc[arc[sta[i]].pre].c += curflow;
  90. }
  91. maxflow += curflow;
  92. u = 0;
  93. }
  94. for(i = sta[u];i != -1;i = arc[i].next)
  95. if(arc[i].c > 0 && dis[arc[i].to] + 1 == dis[u])
  96. break;
  97. if(i != -1)
  98. {
  99. sta[u] = i;
  100. rpath[arc[i].to] = arc[i].pre;
  101. u = arc[i].to;
  102. }
  103. else
  104. {
  105. if((-- cnt[dis[u]]) == 0)
  106. break;
  107. int Min = n + 2;
  108. sta[u] = head[u];
  109. for(i = head[u];i != -1;i = arc[i].next)
  110. if(arc[i].c > 0)
  111. Min = min(Min,dis[arc[i].to]);
  112. dis[u] = Min + 1;
  113. cnt[dis[u]] ++;
  114. if(u != 0)
  115. u = arc[rpath[u]].to;
  116. }
  117. }
  118. return maxflow;
  119. }
  120. bool solve()
  121. {
  122. int i;
  123. sum = 0;
  124. for(i = 1;i <= n;i ++)
  125. {
  126. if(in[i] > out[i])
  127. {
  128. if((in[i] - out[i])&1)
  129. return false;
  130. build(i,n + 1,(in[i] - out[i])>>1);
  131. }
  132. if(in[i] < out[i])
  133. {
  134. if((out[i] - in[i])&1)
  135. return false;
  136. build(0,i,(out[i] - in[i])>>1);
  137. sum += (out[i] - in[i])>>1;
  138. }
  139. }
  140. return ISAP() == sum;
  141. }
  142. int main()
  143. {
  144. int t;
  145. scanf("%d",&t);
  146. while(t --)
  147. {
  148. init();
  149. if(solve())
  150. puts("possible");
  151. else
  152. puts("impossible");
  153. }
  154. return 0;
  155. }
  156. //200K 0MS

poj2391Ombrophobic Bovines(floyd+二分+拆点+最大流)

分类: 网络流 图论 38人阅读 评论(0)收藏举报网络流图论

题目请戳这里

题目大意:n块草地,每块草地有一些牛,每块草地有雨棚,可以容纳一定量的牛。草地间有路,可以无限通过牛,牛通过某条路有一定的时间。现在求最短的时间让所有的牛都能到雨棚。

题目分析:最大流。题目给的是无向图,所以先跑一遍floyd,求出任意2块草地之间最少的时间。因为牛通过路的时间是累加的,所以要把无向图改成有向图,保证牛走某条路后时间是累加的。方法是拆点,将草地i拆成i和i+n,2个点,源点到每个i建边,边权为草地i初始的牛的数量。每个i+n到汇点建边,边权为第i个草地能容纳的牛的数量。如果i到j有路,那么i和j+n连边,这样保证牛经过i到j的最短路后,不能返回,只能到达汇点,从而实现对牛的路径的控制。要求最短的时间,那么二分时间,每次求一次最大流,流量等于牛的总数才合法。

本题数据范围比较大,要__int64。

详情请见代码:

[cpp] view plaincopyprint?
  1. #include <iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. using namespace std;
  6. const int N = 405;
  7. const int M = 160005;
  8. typedef __int64 ll;
  9. const ll inf = ((ll)1<<38);
  10. ll dist[N][N];
  11. int head[N],dis[N],sta[N],que[N],cnt[N],rpath[N];
  12. int cow[205],stay[205];
  13. struct node
  14. {
  15. int to,c,next,pre;
  16. }arc[M];
  17. int n,m,num,sum;
  18. void build(int s,int e,int cap)
  19. {
  20. arc[num].to = e;
  21. arc[num].c = cap;
  22. arc[num].next = head[s];
  23. head[s] = num ++;
  24. arc[num - 1].pre = num;
  25. arc[num].pre = num - 1;
  26. arc[num].c = 0;
  27. arc[num].to = s;
  28. arc[num].next = head[e];
  29. head[e] = num ++;
  30. }
  31. void floyd()
  32. {
  33. int i,j,k;
  34. for(k = 1;k <= n;k ++)
  35. {
  36. for(i = 1;i <= n;i ++)
  37. for(j = 1;j <= n;j ++)
  38. dist[i][j] = min(dist[i][j],dist[i][k] + dist[k][j]);
  39. }
  40. }
  41. void buildgraph(ll t)
  42. {
  43. memset(head,-1,sizeof(head));
  44. num = 0;
  45. int i,j;
  46. for(i = 1;i <= n;i ++)
  47. {
  48. build(0,i,cow[i]);
  49. build(i,i + n,10000005);
  50. build(i + n,n + n + 1,stay[i]);
  51. for(j = 1;j <= n;j ++)
  52. {
  53. if(dist[i][j] <= t)
  54. build(i,j + n,10000005);
  55. }
  56. }
  57. }
  58. void init()
  59. {
  60. sum = 0;
  61. int i,j,a,b;
  62. ll w;
  63. for(i = 1;i <= n;i ++)
  64. for(j = 1;j <= n;j ++)
  65. dist[i][j] = inf;
  66. scanf("%d",&m);
  67. for(i = 1;i <= n;i ++)
  68. {
  69. scanf("%d%d",&cow[i],&stay[i]);
  70. sum += cow[i];
  71. }
  72. while(m --)
  73. {
  74. scanf("%d%d%I64d",&a,&b,&w);
  75. dist[a][b] = dist[b][a] = min(w,dist[a][b]);
  76. }
  77. floyd();
  78. }
  79. void re_Bfs()
  80. {
  81. int i,front,rear;
  82. for(i = 0;i <= n + n + 1;i ++)
  83. cnt[i] = 0,dis[i] = 10000005;
  84. front = rear = 0;
  85. que[rear ++] = n + n + 1;
  86. cnt[0] = 1;
  87. dis[n + n + 1] = 0;
  88. while(front != rear)
  89. {
  90. int u = que[front ++];
  91. for(i = head[u];i != -1;i = arc[i].next)
  92. {
  93. if(arc[arc[i].pre].c == 0 || dis[arc[i].to] < 10000005)
  94. continue;
  95. dis[arc[i].to] = dis[u] + 1;
  96. cnt[dis[arc[i].to]] ++;
  97. que[rear ++] = arc[i].to;
  98. }
  99. }
  100. }
  101. int ISAP()
  102. {
  103. re_Bfs();
  104. int i,u,maxflow = 0;
  105. for(i = 0;i <= n + n + 1;i ++)
  106. sta[i] = head[i];
  107. u = 0;
  108. while(dis[0] < n + n + 2)
  109. {
  110. if(u == n + n + 1)
  111. {
  112. int curflow = 10000005;
  113. for(i = 0;i != n + n + 1;i = arc[sta[i]].to)
  114. curflow = min(curflow,arc[sta[i]].c);
  115. for(i = 0;i != n + n + 1;i = arc[sta[i]].to)
  116. {
  117. arc[sta[i]].c -= curflow;
  118. arc[arc[sta[i]].pre].c += curflow;
  119. }
  120. maxflow += curflow;
  121. u = 0;
  122. }
  123. for(i = sta[u];i != -1;i = arc[i].next)
  124. if(arc[i].c > 0 && dis[arc[i].to] + 1 == dis[u])
  125. break;
  126. if(i != -1)
  127. {
  128. sta[u] = i;
  129. rpath[arc[i].to] = arc[i].pre;
  130. u = arc[i].to;
  131. }
  132. else
  133. {
  134. if((-- cnt[dis[u]]) == 0)
  135. break;
  136. sta[u] = head[u];
  137. int Min = n + n + 2;
  138. for(i = sta[u];i != -1;i = arc[i].next)
  139. if(arc[i].c > 0)
  140. Min = min(Min,dis[arc[i].to]);
  141. dis[u] = Min + 1;
  142. cnt[dis[u]] ++;
  143. if(u != 0)
  144. u = arc[rpath[u]].to;
  145. }
  146. }
  147. return maxflow;
  148. }
  149. void solve()
  150. {
  151. ll l,r,mid;
  152. l = 0;r = inf - 1;
  153. ll ans = -1;
  154. while(l <= r)
  155. {
  156. mid = (l + r)>>1;
  157. buildgraph(mid);
  158. int tmp = ISAP();
  159. if(tmp == sum)
  160. {
  161. ans = mid;
  162. r = mid - 1;
  163. }
  164. else
  165. l = mid + 1;
  166. }
  167. printf("%I64d\n",ans);
  168. }
  169. int main()
  170. {
  171. while(scanf("%d",&n) != EOF)
  172. {
  173. init();
  174. solve();
  175. }
  176. return 0;
  177. }
  178. //2088K 282MS
 

hdu4725The Shortest Path in Nya Graph(拆点 + 最短路dijkstra | SPFA)

分类: 最短路 图论 165人阅读 评论(1) 收藏 举报最短路图论

题目请戳这里

题目大意:给n个点,m条无向边,边权w,为走这条路的代价。每个点属于某一层,从某层到隔壁层代价都是固定的c,求1到n最短路。

题目分析:最短路。比赛的时候硬上SPFA,结果T出翔了。还是太年轻了啊。

因为每个点可以借助层的属性,到达其他点就有了其他的路径。所以有必要把每层也抽象出额外的点。因为每层的点也是不连通的,就是说如果点i和点j在同一层,并不代表他们之间距离就是0。所以对于层节点,还需要拆点。将每层的点拆成i+n和i + n + n 2个点。i+n表示进入第i层,i+n+n表示从第i层出去。建图的时候如果某点j属于第i层,那么

j--->i + n连一条权为0的边,i + n + n --->j连一条权为0的边。对于层与层之间的关系,因为层抽象出来的点只是一个中间媒介点,所以对于进入第i层的边,只可能通过i+n这个点直接从隔壁层出去,于是i+n--->i +1 + n + n连边,边权c,i + n +1 --->i + n + n连边,边权c。注意虽然第i层被抽象出了i+n和I+ n + n2个点,但他们之间不能连边,因为同一层的点距离不为0,连边了就失去了拆点的意义。

trick:n可以为0。。。

补充:其实这题原来可以不用拆点的。感谢小吉吉提供的思路:每层只用抽象出一个点即可,如果点i属于第j层,那么j+n-->i连边,边权0,表示i属于j层,从j层到i的代价为0,那么如何表示i到j层的代价呢,因为层与层直接的代价是c,i属于j层,那么i到j层的代价是0,直接可以省了,直接建边i-->j - 1,i-->j + 1,边权为c。这样可以少n个点。其实跟拆2个点本质上还是一样的,只是在3n个点的图上做了简化,经过测试,速度和拆3个点差不多,dijkstra和SPFA都可以过。

这题卡SPFA卡的比较厉害,T了n次,后来重写了一下总算过了,不过各种优化也进不了700ms,不过优先队列优化的dijkstra却比较高效了,轻松200+ms。

详情请见代码:

1:dijkstra+优先队列:

[cpp] view plaincopy
  1. #include <iostream>  
  2. #include<cstdio>  
  3. #include<queue>  
  4. #include<cstring>  
  5. #include<algorithm>  
  6. using namespace std;  
  7. const int N = 300005;  
  8. const int M = 10000005;  
  9. const int inf = 0x3f3f3f3f;  
  10.   
  11. int m,n,c,num;  
  12. int head[N];  
  13. int dis[N];  
  14. bool flag[N];  
  15. struct nd  
  16. {  
  17.     int dist,id;  
  18.     bool operator< (const nd &a)const  
  19.     {  
  20.         return dist > a.dist;  
  21.     }  
  22. }ss,st;  
  23. priority_queue<nd>lcm;  
  24. struct node  
  25. {  
  26.     int to,next,w;  
  27. }g[M];  
  28. void build(int s,int e,int w)  
  29. {  
  30.     g[num].to = e;  
  31.     g[num].w = w;  
  32.     g[num].next = head[s];  
  33.     head[s] = num ++;  
  34. }  
  35. void dijkstra()  
  36. {  
  37.     int i,u;  
  38.     ss.dist = 0;  
  39.     ss.id = 1;  
  40.     dis[1] = 0;  
  41.     while(!lcm.empty())  
  42.         lcm.pop();  
  43.     lcm.push(ss);  
  44.     while(!lcm.empty())  
  45.     {  
  46.         ss = lcm.top();  
  47.         lcm.pop();  
  48.         u = ss.id;  
  49.         if(flag[u])  
  50.             continue;  
  51.         flag[u] = true;  
  52.         for(i = head[u];i != -1;i = g[i].next)  
  53.         {  
  54.             if(flag[g[i].to] == false && dis[g[i].to] > dis[u] + g[i].w)  
  55.             {  
  56.                 dis[g[i].to] = dis[u] + g[i].w;  
  57.                 ss.dist = dis[g[i].to];  
  58.                 ss.id = g[i].to;  
  59.                 lcm.push(ss);  
  60.             }  
  61.         }  
  62.     }  
  63. }  
  64. int main()  
  65. {  
  66.     int i,a,b,t,cas = 0;  
  67.     int level;  
  68.     scanf("%d",&t);  
  69.     while(t --)  
  70.     {  
  71.         scanf("%d%d%d",&n,&m,&c);  
  72.         memset(head,-1,sizeof(head));  
  73.         num = 0;  
  74.         for(i = 1;i < n;i ++)  
  75.         {  
  76.             build(n + i + 1,n + n + i,c);  
  77.             build(n + i,n + n + i + 1,c);  
  78.         }  
  79.         for(i = 1;i <= n;i ++)  
  80.         {  
  81.             dis[i] = dis[i + n] = dis[i + n + n] = inf;  
  82.             flag[i] = flag[i + n] = flag[i + n + n] = false;  
  83.             scanf("%d",&level);  
  84.             build(i,n + level,0);  
  85.             build(n + n + level,i,0);  
  86.         }  
  87.         for(i = 1;i <= m;i ++)  
  88.         {  
  89.             scanf("%d%d%d",&a,&b,&level);  
  90.             build(a,b,level);  
  91.             build(b,a,level);  
  92.         }  
  93.         printf("Case #%d: ",++cas);  
  94.         dijkstra();  
  95.         if(dis[n] == inf || n == 0)  
  96.             dis[n] = -1;  
  97.         printf("%d\n",dis[n]);  
  98.     }  
  99.     return 0;  
  100. }  
  101. //234MS 10584K  
2:SPFA:

[cpp] view plaincopy
  1. #include <iostream>  
  2. #include<cstdio>  
  3. #include<queue>  
  4. #include<cstring>  
  5. #include<algorithm>  
  6. using namespace std;  
  7. const int N = 300005;  
  8. const int M = 10000005;  
  9. const int inf = 0x3f3f3f3f;  
  10.   
  11. int m,n,c,num;  
  12. int head[N];  
  13. int dis[N];  
  14. bool flag[N];  
  15. struct nd  
  16. {  
  17.     int dist,id;  
  18.     bool operator< (const nd &a)const  
  19.     {  
  20.         return dist > a.dist;  
  21.     }  
  22. }ss,st;  
  23. int que[M];  
  24. struct node  
  25. {  
  26.     int to,next,w;  
  27. }g[M];  
  28. void build(int s,int e,int w)  
  29. {  
  30.     g[num].to = e;  
  31.     g[num].w = w;  
  32.     g[num].next = head[s];  
  33.     head[s] = num ++;  
  34. }  
  35. void SPFA()  
  36. {  
  37.     int i;  
  38.     dis[1] = 0;  
  39.     flag[1] = true;  
  40.     int front,rear;  
  41.     front = rear = 0;  
  42.     que[rear ++] = 1;  
  43.     while(front != rear)  
  44.     {  
  45.         int u = que[front ++];  
  46.         flag[u] = false;  
  47.         if(front == M)  
  48.             front = 0;  
  49.         for(i = head[u];i != -1;i = g[i].next)  
  50.         {  
  51.             if(dis[g[i].to] > dis[u] + g[i].w)  
  52.             {  
  53.                 dis[g[i].to] = dis[u] + g[i].w;  
  54.                 if(flag[g[i].to] == false)  
  55.                 {  
  56.                     flag[g[i].to] = true;  
  57.                     que[rear ++] = g[i].to;  
  58.                     if(rear == M)  
  59.                         rear = 0;  
  60.                 }  
  61.             }  
  62.         }  
  63.     }  
  64. }  
  65. int main()  
  66. {  
  67.     int i,a,b,t,cas = 0;  
  68.     int level;  
  69.     scanf("%d",&t);  
  70.     while(t --)  
  71.     {  
  72.         scanf("%d%d%d",&n,&m,&c);  
  73.         memset(head,-1,sizeof(head));  
  74.         num = 0;  
  75.         for(i = 1;i < n;i ++)  
  76.         {  
  77.             build(n + i + 1,n + n + i,c);  
  78.             build(n + i,n + n + i + 1,c);  
  79.         }  
  80.         for(i = 1;i <= n;i ++)  
  81.         {  
  82.             dis[i] = dis[i + n] = dis[i + n + n] = inf;  
  83.             flag[i] = flag[i + n] = flag[i + n + n] = false;  
  84.             scanf("%d",&level);  
  85.             build(i,n + level,0);  
  86.             build(n + n + level,i,0);  
  87.         }  
  88.         for(i = 1;i <= m;i ++)  
  89.         {  
  90.             scanf("%d%d%d",&a,&b,&level);  
  91.             build(a,b,level);  
  92.             build(b,a,level);  
  93.         }  
  94.         printf("Case #%d: ",++cas);  
  95.         SPFA();  
  96.         if(dis[n] == inf || n == 0)  
  97.             dis[n] = -1;  
  98.         printf("%d\n",dis[n]);  
  99.     }  
  100.     return 0;  
  101. }  
  102. //906MS 13856K  
  103. //750MS 13856K  
  104. //796MS 13856K