zoukankan      html  css  js  c++  java
  • HDU 1599 find the mincost route (无向图的最小环)

    题意:

      给一个带权无向图,求其至少有3个点组成的环的最小权之和。

    思路:

      (1)DFS可以做,实现了确实可以,只是TLE了。量少的时候应该还是可以水一下的。主要思路就是,深搜过程如果当前点搜到一个点访问过了,而其不是当前点的父亲,则肯定有环,可以更新答案。深搜过程要记录路径和,父亲,是否访问过等等信息,因为图可能有多个连通分量。

     1 #include <bits/stdc++.h>
     2 #define INF 0x7f7f7f7f
     3 #define pii pair<int,int>
     4 #define LL unsigned long long
     5 using namespace std;
     6 const int N=110;
     7 struct node
     8 {
     9     int from, to, cost;
    10     node(){};
    11     node(int from,int to,int cost):from(from),to(to),cost(cost){};
    12 }edge[N*N];
    13 int edge_cnt;
    14 vector<int> vect[N];
    15 
    16 void add_node(int from,int to,int cost)
    17 {
    18     edge[edge_cnt]=node(from, to, cost);
    19     vect[from].push_back(edge_cnt++);
    20 }
    21 
    22 int sum[N], vis[N], inq[N], pre[N], ans;
    23 
    24 void DFS(int x)
    25 {
    26     vis[x]=1;
    27     inq[x]=1;
    28     for(int i=0; i<vect[x].size(); i++)
    29     {
    30         node e=edge[vect[x][i]];
    31         if( inq[e.to] && pre[x]!=e.to )
    32         {
    33             ans=min(ans, sum[x]+e.cost-sum[e.to]);
    34         }
    35         if( !inq[e.to] )
    36         {
    37             pre[e.to]=x;
    38             sum[e.to]=sum[x]+e.cost;
    39             DFS(e.to);
    40             sum[e.to]=0;
    41             pre[e.to]=0;
    42         }
    43     }
    44     inq[x]=0;
    45 }
    46 
    47 int cal(int n)
    48 {
    49     ans=INF;
    50     memset(vis,0,sizeof(vis));
    51     memset(inq,0,sizeof(inq));
    52     memset(pre,0,sizeof(pre));
    53     memset(sum,0,sizeof(sum));
    54     for(int i=1; i<=n; i++)
    55     {
    56         if(!vis[i])
    57             DFS(i);
    58     }
    59     return ans==INF? 0: ans;
    60 }
    61 
    62 int main()
    63 {
    64     freopen("input.txt", "r", stdin);
    65     int t, a, b, c, n, m;
    66     while(~scanf("%d %d", &n, &m))
    67     {
    68         edge_cnt=0;
    69         for(int i=0; i<=n; i++) vect[i].clear();
    70 
    71         for(int i=0; i<m; i++)
    72         {
    73             scanf("%d%d%d",&a,&b,&c);
    74             add_node(a, b, c);
    75             add_node(b, a, c);
    76         }
    77         
    78         int ans=cal(n);
    79         if(ans) printf("%d
    ", ans);
    80         else    printf("It's impossible.
    ");
    81     }
    82     return 0;
    83 }
    TLE代码

      (2)dijkstra。枚举删除某一条边,求该边两点间的最短距离。要注意的是,重边只留1条权最小的,其他删掉,这样就能保证至少出现3个点。

      608ms

      1 #include <bits/stdc++.h>
      2 #include <iostream>
      3 #include <cstdio>
      4 #include <vector>
      5 #include <cstring>
      6 #include <deque>
      7 #define INF 0x7f7f7f7f
      8 #define pii pair<int,int>
      9 #define LL unsigned long long
     10 using namespace std;
     11 const int N=110;
     12 struct node
     13 {
     14     int from, to, cost, tag;
     15     node(){};
     16     node(int from,int to,int cost):from(from),to(to),cost(cost),tag(1){};
     17 }edge[N*N];
     18 int edge_cnt;
     19 vector<int> vect[N];
     20 int g[N][N];
     21 void add_node(int from,int to,int cost)
     22 {
     23     edge[edge_cnt]=node(from, to, cost);
     24     vect[from].push_back(edge_cnt++);
     25 }
     26 
     27 
     28 int vis[N], cost[N];
     29 int dijkstra(int s,int e)
     30 {
     31     memset(cost, 0x7f, sizeof(cost));
     32     memset(vis, 0, sizeof(vis));
     33     cost[s]=0;
     34     priority_queue<pii,vector<pii>,greater<pii> > que;
     35     que.push(make_pair(0, s));
     36 
     37     while(!que.empty())
     38     {
     39         int x=que.top().second;
     40         que.pop();
     41         if(vis[x])  continue;
     42         vis[x]=1;
     43         for(int i=0; i<vect[x].size(); i++)
     44         {
     45             node e=edge[vect[x][i]];
     46             if( e.tag && cost[e.to]>cost[x]+e.cost )
     47             {
     48                 cost[e.to]=cost[x]+e.cost;
     49                 que.push(make_pair(cost[e.to], e.to));
     50             }
     51         }
     52     }
     53     return cost[e];
     54 
     55 }
     56 
     57 int cal()
     58 {
     59     int ans=INF;
     60     for(int i=0; i<edge_cnt; i+=2)
     61     {
     62         edge[i].tag=0;
     63         edge[i^1].tag=0;
     64         ans=min(ans, edge[i].cost+dijkstra(edge[i].from, edge[i].to));
     65         edge[i].tag=1;
     66         edge[i^1].tag=1;
     67     }
     68     return ans==INF? 0: ans;
     69 }
     70 
     71 int main()
     72 {
     73     freopen("input.txt", "r", stdin);
     74     int t, a, b, c, n, m;
     75     while(~scanf("%d %d", &n, &m))
     76     {
     77         edge_cnt=0;
     78         for(int i=0; i<=n; i++) vect[i].clear();
     79         memset(g, 0x7f, sizeof(g));
     80 
     81         for(int i=0; i<m; i++)
     82         {
     83             scanf("%d%d%d",&a,&b,&c);
     84             g[b][a]=g[a][b]=min(g[a][b], c);
     85         }
     86         for(int i=1; i<=n; i++) //为了去重边
     87         {
     88             for(int j=i+1; j<=n; j++)
     89             {
     90                 if(g[i][j]<INF)
     91                 {
     92                     add_node(i, j, g[i][j]);
     93                     add_node(j, i, g[i][j]);
     94                 }
     95             }
     96         }
     97         int ans=cal();
     98         if(ans) printf("%d
    ", ans);
     99         else    printf("It's impossible.
    ");
    100     }
    101     return 0;
    102 }
    AC代码

      (3)floyd。dijkstra是枚举删某条边,而floyd是枚举相连的两条边。先理解floyd的思想,穷举每个点k作为中间节点来更新其他点a和b之间的距离,而当某个点未被k枚举到时,是不可能有一条路径将其包含在中间的,它顶多可以作为路径的起点或者终点。利用这点,在未枚举到某点k作为中间点时,可以枚举一下与k相连的两条边,即i->k->j。

       78ms

     1 #include <bits/stdc++.h>
     2 #define INF 0x7f7f7f7f
     3 #define pii pair<int,int>
     4 #define LL unsigned long long
     5 using namespace std;
     6 const int N=110;
     7 int g[N][N], dist[N][N];
     8 
     9 
    10 int cal(int n)  //floyd
    11 {
    12     int ans=INF;
    13     for(int k=1; k<=n; k++) //注意枚举顺序。
    14     {
    15         //枚举两条边i->k->j。
    16         for(int i=1; i<=n; i++ )
    17         {
    18             if(g[i][k]==INF || k==i) continue;
    19             for(int j=i+1; j<=n; j++)   //i和j不能相等,才能保证至少3个点。
    20             {
    21                 if(g[k][j]==INF || dist[i][j]==INF || k==j )    continue;
    22                 int dis=g[i][k] + g[k][j] + dist[i][j];
    23                 ans=min(ans, dis);
    24             }
    25         }
    26         for(int i=1; i<=n; i++)
    27         {
    28             for(int j=1; j<=n; j++)
    29             {
    30                 if(dist[i][k]==INF || dist[k][j]==INF) continue;
    31                 dist[i][j]=min(dist[i][j], dist[i][k]+dist[k][j]);
    32             }
    33         }
    34     }
    35 
    36     return ans==INF? 0: ans;
    37 }
    38 
    39 int main()
    40 {
    41     freopen("input.txt", "r", stdin);
    42     int t, a, b, c, n, m;
    43     while(~scanf("%d %d", &n, &m))
    44     {
    45         memset(g, 0x7f, sizeof(g));
    46         for(int i=0; i<m; i++)
    47         {
    48             scanf("%d%d%d",&a,&b,&c);
    49             g[b][a]=g[a][b]=min(g[a][b], c);
    50         }
    51         memcpy(dist, g, sizeof(g));
    52         for(int i=1; i<=n; i++) dist[i][i]=0;
    53 
    54         int ans=cal(n);
    55         if(ans) printf("%d
    ", ans);
    56         else    printf("It's impossible.
    ");
    57     }
    58     return 0;
    59 }
    AC代码
  • 相关阅读:
    77. Combinations
    76. Minimum Window Substring
    75. Sort Colors
    74. Search a 2D Matrix
    73. Set Matrix Zeroes
    72. Edit Distance
    71. Simplify Path
    70. Climbing Stairs
    线段树+欧拉函数——cf1114F
    区间dp——好题cf1132F
  • 原文地址:https://www.cnblogs.com/xcw0754/p/4695779.html
Copyright © 2011-2022 走看看