• 最短路题单练习


    1.Frogger(最大路径最小值)

    题目链接

     题目大意:求所有路径中的最长的边,在这些最长边中找到最小值并输出

    思路:我们可以改变dijkstra的dis数组的含义,即所有点到点v的路径上的最小值,例如现在有一条路径为 u->v,我们可以用 dis[u] 和 len(u->v)的长度取最大,再用此时的得到的值,与dis[v]取最小

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. using namespace std;
    7. const int maxn = 220;
    8. const double INF = 1e60;
    9. int n;
    10. double G[maxn][maxn], d[maxn];
    11. struct Pos {
    12. int x, y;
    13. }num[maxn];
    14. double calc(int i, int j) {
    15. return (sqrt(pow((double)num[i].x-num[j].x, 2)+pow((double)num[i].y-num[j].y, 2)));
    16. }
    17. double dijkstra() {
    18. bool vis[maxn];
    19. memset(vis, false, sizeof(vis));
    20. for(int i=0; i
    21. d[i] = G[0][i];
    22. }
    23. d[0] = 0;
    24. vis[0] = true;
    25. for(int i=0; i-1; i++) {
    26. double m = INF; int x;
    27. for(int y=0; yif(!vis[y] && m >= d[y]) m = d[x=y];
    28. vis[x] = true;
    29. for(int y=0; y
    30. if(!vis[y]) {
    31. double maxx = max(d[x], G[x][y]);
    32. if(d[y] > maxx) d[y] = maxx;
    33. }
    34. }
    35. }
    36. return d[1];
    37. }
    38. int main() {
    39. int cnt = 0;
    40. while(scanf("%d", &n) == 1) {
    41. if(n == 0) break;
    42. for(int i=0; iscanf("%d%d", &num[i].x, &num[i].y);
    43. for(int i=0; i
    44. for(int j=0; j
    45. G[i][j] = G[j][i] = calc(i, j);
    46. }
    47. G[i][i] = 0;
    48. }
    49. printf("Scenario #%d\nFrog Distance = %.3f\n\n", ++cnt, dijkstra());
    50. }
    51. return 0;
    52. }

    2.Heavy Transportation(最小路径最大值)

    题目链接

    题目大意:N个点,M条边,每条边有权值。求一条1号点到N号点的路径,要求使得路径中的边权最小值最大。

    思路:这道题和上一道思路类似,我们可以改变dis数组的含义,在更新dis的过程中与上一道题相反即可

    1. #include
    2. #include
    3. using namespace std;
    4. const int N = 1010, M = 1e6+10;
    5. int h[N], e[M], ne[M], w[M], idx;
    6. int dis[N],vis[N];
    7. int n,m;
    8. void add(int a,int b,int c){
    9. e[idx] = b;
    10. ne[idx] = h[a];
    11. w[idx] = c;
    12. h[a] = idx++;
    13. }
    14. int dj(){
    15. for(int i=h[1];~i;i=ne[i]){
    16. int j = e[i];
    17. dis[j] = w[i];
    18. }
    19. for(int i=0;i
    20. int t = -1;
    21. for(int j=1;j<=n;j++){
    22. if(!vis[j]&&(t==-1||dis[t]
    23. t = j;
    24. }
    25. }
    26. vis[t] = 1;
    27. for(int i = h[t]; ~i ; i = ne[i]){
    28. int j = e[i];
    29. int minn = min(w[i],dis[t]);
    30. dis[j] = max(dis[j],minn);
    31. }
    32. }
    33. return dis[n];
    34. }
    35. int main(){
    36. int t;
    37. scanf("%d",&t);
    38. int cnt=0;
    39. while(t--){
    40. scanf("%d%d",&n,&m);
    41. memset(h,-1,sizeof h);
    42. idx = 0;
    43. memset(vis,0,sizeof vis);
    44. memset(dis,-0x3f,sizeof dis);
    45. while(m--){
    46. int a ,b,c;
    47. scanf("%d%d%d",&a,&b,&c);
    48. add(a,b,c);
    49. add(b,a,c);
    50. }
    51. printf("Scenario #%d:\n%d\n\n",++cnt,dj());
    52. }
    53. }

    判断正环的题目

    Currency Exchange

     思路:如果有正环,那么一定可以循环无限次,让初始值变正

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. const int N = 200, M = N * 2;
    6. int h[N],e[M],ne[M],idx;
    7. double wr[M],w[M];
    8. int vis[N];
    9. double dis[N];
    10. int cnt[N];
    11. int n,m,s;
    12. double st;
    13. void add(int a,int b,double r,double c){
    14. e[idx] = b;
    15. ne[idx] = h[a];
    16. wr[idx] = r;
    17. w[idx] = c;
    18. h[a] = idx++;
    19. }
    20. bool spfa(int s)
    21. {
    22. queue<int > q;
    23. q.push(s);
    24. vis[s] = true;
    25. dis[s] = st;
    26. for (int i = 1; i <= n; i ++)
    27. {
    28. if(i==s)continue;
    29. q.push(i);
    30. vis[i] = 1;
    31. }
    32. while (!q.empty())
    33. {
    34. int t = q.front();
    35. q.pop();
    36. vis[t] = false;
    37. for (int i = h[t]; ~i; i = ne[i])
    38. {
    39. int j = e[i];
    40. if ((dis[t] - w[i]) * wr[i] > dis[j])
    41. {
    42. dis[j] = (dis[t] - w[i]) * wr[i];
    43. cnt[j] = cnt[t] + 1;
    44. if (cnt[j] >= n) return true;
    45. if (!vis[j])
    46. {
    47. q.push(j);
    48. vis[j] = true;
    49. }
    50. }
    51. }
    52. }
    53. return false;
    54. }
    55. int main(){
    56. cin >> n >> m >> s >>st;
    57. memset(h,-1,sizeof h);
    58. while(m--){
    59. int a,b;
    60. double r1,r2,c1,c2;
    61. cin >> a >> b >> r1 >> c1 >> r2 >> c2;
    62. add(a,b,r1,c1);
    63. add(b,a,r2,c2);
    64. }
    65. if(spfa(s)){
    66. puts("YES");
    67. }
    68. else{
    69. puts("NO");
    70. }
    71. }

    相关题目:https://vjudge.net/problem/POJ-3259

    MPI Maelstrom

    MPI Maelstrom - POJ 1502 - Virtual Judge

    题目大意:

    题目大意:给定一个下三角矩阵,询问从1开始到其他点的最短路径中,最长的那个是多少

    思路:其实就是一个很简单的dijkstra的板子题,我们可以一遍dijkstra,跑一遍最短路,找到最大的值输出即可

    代码复制的别人的

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. const int N=110;
    6. #define MAX 0x7fffffff
    7. int map[N][N];
    8. int dis[N],visted[N],n;
    9. int dijkstra(){
    10. memset(visted,0,sizeof(visted));
    11. for(int i=0;i<=n;++i){
    12. dis[i]=MAX;
    13. }
    14. dis[1]=0;
    15. int pos=1;visted[pos]=1;
    16. for(int i=1;i<=n;++i){
    17. for(int j=1;j<=n;++j){
    18. if(!visted[j]&&map[pos][j]!=MAX&&dis[j]>dis[pos]+map[pos][j])
    19. dis[j]=dis[pos]+map[pos][j];
    20. }
    21. int mmin=MAX;
    22. for(int j=1;j<=n;++j){
    23. if(!visted[j]&&dis[j]
    24. mmin=dis[j];
    25. pos=j;
    26. }
    27. }
    28. //printf("pos==%d\n",pos);
    29. visted[pos]=1;
    30. }
    31. int mmax=0;
    32. for(int i=1;i<=n;++i){
    33. //printf("%d ",dis[i]);
    34. if(mmax
    35. mmax=dis[i];
    36. }
    37. //cout<
    38. return mmax;
    39. }
    40. int main(){
    41. //freopen("1.txt","r",stdin);
    42. while(~scanf("%d",&n)){
    43. int m;
    44. char x;
    45. for(int i=2;i<=n;++i){
    46. for(int j=1;j
    47. if(scanf("%d",&m)!=0)
    48. map[i][j]=map[j][i]=m;
    49. else{
    50. map[i][j]=map[j][i]=MAX;
    51. scanf("%c",&x);
    52. }
    53. }
    54. }
    55. for(int i=1;i<=n;++i)
    56. map[i][i]=0;
    57. int xx=dijkstra();
    58. printf("%d\n",xx);
    59. }
    60. return 0;
    61. }

    Cow Contest(floyd + 传递闭包)

    Cow Contest - POJ 3660 - Virtual Judge

    题目大意:有N头牛,评以N个等级,各不相同,先给出部分牛的等级的高低关系,问最多能确定多少头牛的等级

    思路:如果有一头关系已经确定, 那么他一定与其他所有牛关系已经确定了,即n-1头牛

    1. #include
    2. #include
    3. using namespace std;
    4. const int N = 110, M = N * 2;
    5. int g[N][N];
    6. int n,m;
    7. void floyd(){
    8. for(int k=1;k<=n;k++){
    9. for(int i=1;i<=n;i++){
    10. for(int j=1;j<=n;j++){
    11. g[i][j]|=g[i][k]&&g[k][j];
    12. }
    13. }
    14. }
    15. }
    16. int main(){
    17. cin >> n >> m;
    18. while(m--){
    19. int a, b;
    20. cin >> a >> b;
    21. g[a][b] = 1;
    22. }
    23. floyd();
    24. int res = 0;
    25. for(int i=1;i<=n;i++){
    26. int cnt = 0;
    27. for(int j=1;j<=n;j++){
    28. if(g[i][j]||g[j][i]) cnt++;
    29. }
    30. if(cnt==n-1)res++;
    31. }
    32. cout << res <
    33. }

    Arbitrage

    套利是指利用货币汇率的差异,将一种货币的一个单位转换为同一货币的多个单位。例如,假设1美元买0.5英镑,1英镑买10.0法国法郎,1法国法郎买0.21美元。然后,通过兑换货币,聪明的交易者可以从1美元开始,购买0.5 * 10.0 * 0.21 = 1.05美元,获得5%的利润。
    您的工作是编写一个程序,以货币汇率列表作为输入,然后确定是否可能进行套利。

    输入:

    将包含一个或多个测试用例。每个测试用例的第一行有一个整数n (1<=n<=30),表示不同货币的数量。接下来的n行每一行都包含一种货币的名称。名称中不会出现空格。下一行包含一个整数m,表示接下来的表的长度。最后的m行分别包含源货币的名称ci、表示从ci到cj的汇率的实数rij和目标货币的名称cj。没有出现在表格中的交易是不可能的。

    测试用例通过空行彼此分开。对于n,输入以0(0)的值结束

    思路:和上面找正环的思路差不多

    1. //floyed
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. using namespace std;
    10. int n,m;
    11. double dist[40][40];
    12. mapint> money;
    13. void init()
    14. {
    15. for(int i = 0;i < n;i++) {
    16. for(int j = 0;j < n;j++){
    17. if(i == j) dist[i][j] = 1;
    18. else dist[i][j] = 0;
    19. }
    20. }
    21. }
    22. void floyd()
    23. {
    24. for(int k = 0;k < n;k++) {
    25. for(int i = 0;i < n;i++) {
    26. for(int j = 0;j < n;j++) {
    27. if(dist[i][j] < dist[i][k] * dist[k][j])
    28. dist[i][j] = dist[i][k] * dist[k][j];
    29. }
    30. }
    31. }
    32. }
    33. int main()
    34. {
    35. int cas = 1;
    36. string s,ss;
    37. double r;
    38. while(~scanf("%d",&n) &&n) {
    39. init();
    40. for(int i = 0;i < n;i++) {
    41. cin >> s;
    42. money[s] = i;
    43. }
    44. cin >> m;
    45. for(int i = 0;i < m;i++) {
    46. cin >> s >> r >> ss;
    47. dist[money[s] ][money[ss] ] = r;
    48. }
    49. floyd();
    50. printf("Case %d: ",cas++);
    51. for(int i = 0;i < n;i++) {
    52. if(dist[i][i] > 1) {
    53. cout << "Yes" << endl;
    54. break;
    55. }
    56. else if(i == n - 1)
    57. cout << "No" <
    58. }
    59. }
    60. return 0;
    61. }

    差分约束见另外一篇文章

  • 相关阅读:
    Netty 进阶学习(十)-- 协议设计与解析
    JavaScript 63 JavaScript 对象 63.4 JavaScript 显示对象
    Eclipse连接Mysql超详细教程
    JSR303校验,分组校验,自定义注解校验,全局异常处理
    C# 压缩图片
    【快应用】网络图片保存到相册失败案例
    lftp服务与http服务(包含scp服务)详解
    Unity开发过程中的一些小知识点
    Linux中使用Docker安装ElasticSearch7.10.x集群
    uniapp搜索功能
  • 原文地址:https://blog.csdn.net/qq_52280112/article/details/126173559