[关闭]
@Asuna 2017-02-21T19:45:00.000000Z 字数 4696 阅读 844

2016寒假集训队第九次作业

题解


Problem A:最短路

题意:寻找最短的从商店到赛场的路线。

题解:最短路模版题。mark一下模版。
http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. using namespace std;
  5. int d[110],w[110][110],vis[110],n,m,a,b,c;
  6. void dijkstra(int s)
  7. {
  8. for (int i=1; i<=n; i++)
  9. d[i]=10000000;
  10. d[s] = 0;
  11. memset(vis, 0, sizeof(vis));
  12. for (int i=1; i<=n; i++)
  13. {
  14. int u=-1;
  15. for (int j=1; j<=n; j++)
  16. if (!vis[j])
  17. {
  18. if (u==-1 || d[j]<d[u]) u=j;
  19. }
  20. vis[u]=1;
  21. for (int j=1; j<=n; j++)
  22. if (!vis[j])
  23. {
  24. int tmp=d[u]+w[u][j];
  25. if (tmp<d[j]) d[j]=tmp;
  26. }
  27. }
  28. }
  29. int main()
  30. {
  31. while(cin>>n>>m)
  32. {
  33. if (n==0 && m==0) break;
  34. for (int i=1; i<=n; i++)
  35. {
  36. w[i][i]=10000000;
  37. for (int j=i+1; j<=n; j++)
  38. w[i][j]=w[j][i]=100000000;
  39. }
  40. for (int i=0; i<m; i++)
  41. {
  42. cin>>a>>b>>c;
  43. w[a][b]=w[b][a]=c;
  44. }
  45. dijkstra(1);
  46. cout<<d[n]<<endl;
  47. }
  48. return 0;
  49. }

Problem B: Wormholes

题意:已知从一个农场到另一个农场的一些通道和所需的时间,一些虫洞(虫洞是单向通道,可以回到前一段时间),问这个人能否回到起始地方。

题解:构造出图,将农田抽象成点,通道抽象成边,这样可以将虫洞抽象成负边,判断是否存在负环,这样就可以用Bellman_Ford求解。

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<stack>
  5. #include<algorithm>
  6. using namespace std;
  7. struct node
  8. {
  9. int u,v,w;
  10. }que[10010];
  11. int t,n,m,wh,cnt,inf=999999999,dis[5010],t1,t2,t3;
  12. bool bellman_ford()
  13. {
  14. memset(dis,inf,sizeof(dis));
  15. dis[1]=0;
  16. int flag,a,b,c;
  17. for (int i=1; i<n; i++)
  18. {
  19. flag=0;
  20. for (int j=0; j<cnt; j++)
  21. {
  22. a=que[j].u;
  23. b=que[j].v;
  24. c=que[j].w;
  25. if (dis[b]>dis[a]+c)
  26. {
  27. dis[b]=dis[a]+c;
  28. flag=1;
  29. }
  30. }
  31. if(!flag)
  32. break;
  33. }
  34. for (int j=0; j<cnt; j++)
  35. {
  36. a=que[j].u;
  37. b=que[j].v;
  38. c=que[j].w;
  39. if(dis[b]>dis[a]+c)
  40. return true;
  41. }
  42. return false;
  43. }
  44. int main()
  45. {
  46. cin>>t;
  47. while (t--)
  48. {
  49. cnt=0;
  50. cin>>n>>m>>wh;
  51. for(int i=1; i<=m; i++)
  52. {
  53. cin>>t1>>t2>>t3;
  54. que[cnt].u=t1;
  55. que[cnt].v=t2;
  56. que[cnt].w=t3;
  57. cnt++;
  58. que[cnt].u=t2;
  59. que[cnt].v=t1;
  60. que[cnt].w=t3;
  61. cnt++;
  62. }
  63. for (int i=m+1; i<=m+wh; i++)
  64. {
  65. cin>>t1>>t2>>t3;
  66. que[cnt].u=t1;
  67. que[cnt].v=t2;
  68. que[cnt].w=-t3;
  69. cnt++;
  70. }
  71. if (bellman_ford()) cout<<"YES"<<endl;
  72. else cout<<"NO"<<endl;
  73. }
  74. return 0;
  75. }

Problem C:tockbroker Grapevine

题意:每个人传递消息同时进行,求最后一个人知道消息的最短时间。

题解:先枚举每个人为起点的情况,然后这个情况下求每个人知道消息的最短时间,然后遍历一遍找到最大的那个,就是最后一个人收到消息的时间了。然后比较出所以情况中最后一个人知道消息的时间的最小值。

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<cstdlib>
  5. #include<algorithm>
  6. #include<cmath>
  7. using namespace std;
  8. int n,dis[10010],a[1010][1010],book[10010],minn,v,m,x,y,maxx,k;
  9. void dijstra(int s)
  10. {
  11. for (int i=1; i<=n; i++) dis[i]=99999999;
  12. dis[s]=0;
  13. for (int i=1; i<=n; i++)
  14. book[i]=0;
  15. for (int i=1; i<=n; i++)
  16. {
  17. int minn=99999999;
  18. for (int j=1; j<=n; j++)
  19. {
  20. if (dis[j]<minn && book[j]==0)
  21. {
  22. minn=dis[j];
  23. v=j;
  24. }
  25. }
  26. book[v]=1;
  27. for (int j=1; j<=n; j++)
  28. {
  29. if (book[j]==0)
  30. {
  31. if (dis[j]>dis[v]+a[v][j])
  32. {
  33. dis[j]=dis[v]+a[v][j];
  34. }
  35. }
  36. }
  37. }
  38. return;
  39. }
  40. int main()
  41. {
  42. while(cin>>n)
  43. {
  44. if (n==0) break;
  45. for (int i=1; i<=n; i++)
  46. {
  47. for (int j=1; j<=n; j++)
  48. {
  49. if (i<=j)
  50. a[i][j]=a[j][i]=99999999;
  51. }
  52. }
  53. for (int i=1; i<=n; i++)
  54. {
  55. cin>>m;
  56. for(int j=1; j<=m; j++)
  57. {
  58. cin>>x>>y;
  59. a[i][x]=y;
  60. }
  61. }
  62. minn=99999999;
  63. k=0;
  64. for (int i=1; i<=n; i++)
  65. {
  66. dijstra(i);
  67. maxx=0;
  68. for (int j=1; j<=n; j++)
  69. {
  70. if (j!=i)
  71. {
  72. if (dis[j]>maxx) maxx=dis[j];
  73. }
  74. }
  75. //cout<<maxx<<" "<<minn<<endl;
  76. if (maxx<minn)
  77. {
  78. minn=maxx;
  79. k=i;
  80. }
  81. }
  82. if (k!=0) cout<<k<<" "<<minn<<endl;
  83. else cout<<"disjoint"<<endl;
  84. }
  85. return 0;
  86. }

Problem D:昂贵的聘礼

题意:娶到酋长女儿的最小代价,即到达终点的最短距离。

题解:枚举的最小等级,枚举过程中把小于这个等级,差距大于m的删去。

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<cmath>
  5. using namespace std;
  6. int w[110][110],n,m,x,k,minn,l[110],p[110],dis[110],vis[110],within[110],boss,cost,ans;
  7. int dijkstra ()
  8. {
  9. int k,minn;
  10. memset(vis,0,sizeof(vis));
  11. for (int i=1; i<=n; i++)
  12. dis[i]=w[1][i];
  13. dis[1]=0;
  14. vis[1]=1;
  15. for (int i=1; i<=n; i++)
  16. {
  17. minn=999999999;
  18. for (int j=1; j<=n; j++)
  19. {
  20. if (!vis[j] && within[j] && dis[j]<minn)
  21. {
  22. k=j;
  23. minn=dis[j];
  24. }
  25. }
  26. if (minn==999999999)
  27. break;
  28. vis[k]=1;
  29. dis[k]=minn;
  30. for (int j=1; j<=n; j++)
  31. if (!vis[j] && within[j] && dis[k]+w[k][j]<dis[j])
  32. dis[j]=dis[k]+w[k][j];
  33. }
  34. minn=999999999;
  35. for (int i=1; i<=n; i++)
  36. if (dis[i]+p[i]<minn && vis[i])
  37. minn=dis[i]+p[i];
  38. return minn;
  39. }
  40. int main()
  41. {
  42. cin>>m>>n;
  43. for (int i=1; i<=n; i++)
  44. for (int j=1; j<=n; j++)
  45. if (i==j) w[i][j]=0;
  46. else w[i][j]=999999999;
  47. for (int i=1; i<=n; i++)
  48. {
  49. cin>>p[i]>>l[i]>>x;
  50. for (int j=0; j<x; j++)
  51. {
  52. cin>>k;
  53. cin>>w[i][k];
  54. }
  55. }
  56. boss=l[1];
  57. ans=999999999;
  58. for (int i=0; i<=m; i++)
  59. {
  60. memset(within,0,sizeof(within));
  61. for (int j=1; j<=n; j++)
  62. {
  63. if (boss-l[j]<=m-i && l[j]-boss<=i)
  64. within[j]=1;
  65. }
  66. cost=dijkstra();
  67. if (cost<ans) ans=cost;
  68. }
  69. cout<<ans<<endl;
  70. return 0;
  71. }

Problem F:Choose the best route

题意:给定一个有向图,多个起点,一个终点,求起点到终点的最短路。

题解:将0看成出发点,将n个能选择的点看做事0的相邻并且花费为0的点,那么就是求0到S的最小花费了。

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. using namespace std;
  6. int n,m,s,x,y,t,w[1005][1005],vis[1005],dis[1005];
  7. void dijkstra()
  8. {
  9. int minn,k;
  10. memset(vis,0,sizeof(vis));
  11. vis[0]=1;
  12. for (int i=0; i<=n; i++)
  13. dis[i]=w[0][i];
  14. for (int i=0; i<=n; i++)
  15. {
  16. minn=100000000;
  17. for (int j=0; j<=n; j++)
  18. {
  19. if (dis[j]<minn && !vis[j])
  20. {
  21. k=j;
  22. minn=dis[j];
  23. }
  24. }
  25. vis[k]=1;
  26. for (int j=0; j<=n; j++)
  27. {
  28. if (dis[k]+w[k][j]<dis[j] && !vis[j])
  29. dis[j]=dis[k]+w[k][j];
  30. }
  31. }
  32. }
  33. int main()
  34. {
  35. while(cin>>n>>m>>s)
  36. {
  37. for (int i=0; i<=n; i++)
  38. for (int j=0; j<=n; j++)
  39. w[i][j]=100000000;
  40. for (int i=1; i<=m; i++)
  41. {
  42. scanf("%d%d%d",&x,&y,&t);
  43. if (t<w[x][y])
  44. w[x][y]=t;
  45. }
  46. cin>>m;
  47. for (int i=1; i<=m; i++)
  48. {
  49. scanf("%d",&x);
  50. w[0][x]=0;
  51. }
  52. dijkstra();
  53. if (dis[s]==100000000) cout<<-1<<endl;
  54. else cout<<dis[s]<<endl;
  55. }
  56. return 0;
  57. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注