USACO 4.1 Fence Loops (fence6)

/*
    这题是求无向图中的一个最小环的长度。
主要思路是:因为边都是直线,边的两点之间的最短距离必然是这个边长。那么,
再求一条到两顶点的最短距径,这个路径与边构成了一个环。这个环是包含该边的最小环。
枚举一下所有边,计算出最小环即可。对于每个边,删除该边,然后计算两顶点的最短路径,再恢复该边。
    但是这个图的输入是用边表示的,一个难点就是将其转换成用点表示。这里用边的集合来表示一个点。
然后用map<set<int>,int>来存储某一边对应的边的编号。每找到一个新的顶点则分配一个新的编号。这部
分主要通过函数get_vertex(set<int>&s)来实现。
refer to 止于自娱
*/
/*
Executing...
   Test 1: TEST OK [0.000 secs, 3552 KB]
   Test 2: TEST OK [0.011 secs, 3552 KB]
   Test 3: TEST OK [0.011 secs, 3552 KB]
   Test 4: TEST OK [0.011 secs, 3552 KB]
   Test 5: TEST OK [0.011 secs, 3552 KB]
   Test 6: TEST OK [0.011 secs, 3552 KB]
   Test 7: TEST OK [0.011 secs, 3552 KB]
   Test 8: TEST OK [0.022 secs, 3552 KB]
   Test 9: TEST OK [0.022 secs, 3552 KB]

All tests OK.
Your program ('fence6') produced all correct answers!  This is your
submission #2 for this problem.  Congratulations!
*/

/*
ID: haolink1
PROG: fence6
LANG: C++
*/

//#include <iostream>
#include <fstream>
#include <set>
#include <map>

using namespace std;

ifstream fin("fence6.in");
ofstream cout("fence6.out");

class Edge{public: int va_,vb_,len_;};
const int INF = 0x7fffffff/2;
const int MAX = 100; 
int edge_num;
int vertex_num;
int graph[MAX][MAX];
Edge edges[MAX];

int GetVertex(set<int>& s){
    static map<set<int>,int> vertexs;
    if(vertexs.find(s) == vertexs.end()){
        vertexs[s] = vertex_num;
        return vertex_num++;
    }else return vertexs[s];
}

void BuildGraph(){
    fin >> edge_num; 
    for(int i = 0; i < MAX; i++){
        for(int j = 0; j < MAX; j++){
            graph[i][j] = INF;
        }
    }
    for(int i = 0; i < edge_num; i++){
        int cur_edge = 0,len = 0,l_num = 0,r_num = 0,tmp = 0;
        fin >> cur_edge >> len >> l_num >> r_num;
        set<int> s;
        s.insert(cur_edge);
        for(int j = 0; j < l_num; j++){
            fin >> tmp;
            s.insert(tmp);
        }
        int l_v = GetVertex(s);
        s.clear();
        s.insert(cur_edge);
        for(int j = 0; j < r_num; j++){
            fin >> tmp;
            s.insert(tmp);
        }
        int r_v = GetVertex(s);
        graph[l_v][r_v] = graph[r_v][l_v] = len;
        edges[i].va_ = l_v; edges[i].vb_ = r_v; edges[i].len_ = len;
    }
}
int v_dist[MAX];
bool v_visited[MAX];

int ExtractMin(){
    int min = INF,index = -1;
    for(int i = 0; i < vertex_num; i++){
        if(v_visited[i] == 0 && v_dist[i] < min ){
            min = v_dist[i];
            index = i;
        }
    }
    if(index != -1) v_visited[index] = 1;
    return index;
}

int DIJKSTRA(int source, int des){
    for(int i = 0; i < vertex_num; i++){
        v_dist[i] = INF;
        v_visited[i] = 0;
    }
    v_dist[source] = 0;
    while(1){
        int cur_v = ExtractMin(); 
        if (cur_v == des)//Note this case means source can reach des, also use it for efficiency;
            return v_dist[des];
        else if(cur_v == -1) //Note this case means source cannot reach des;
            return INF;
        for(int i = 0; i < vertex_num; i++){
            if(v_dist[i] > v_dist[cur_v] + graph[cur_v][i])
                v_dist[i] = v_dist[cur_v] + graph[cur_v][i];
        }          
    }
}

int main(){
    BuildGraph();
    int min_perimeter = INF; 
    //int min_index = -1;
    for(int i = 0; i < edge_num; i++){
        int va = edges[i].va_,vb = edges[i].vb_;
        int len = graph[va][vb];
        graph[va][vb] = graph[vb][va] = INF;
        int min_path = DIJKSTRA(va,vb);
        if(min_perimeter > len + min_path){ 
            min_perimeter = len + min_path;
      //      min_index = i;
        }
        //Note to retore;
        graph[va][vb] = graph[vb][va] = len;
    }
    
    //cout << min_index << endl;
    cout << min_perimeter << endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值