V - Pandaland (最小环,堆优化的Dijkstra)

Mr. Panda lives in Pandaland. There are many cities in Pandaland. Each city can be treated as a point on a 2D plane. Different cities are located in different locations. 
There are also M bidirectional roads connecting those cities. There is no intersection between two distinct roads except their endpoints. Besides, each road has a cost w. 
One day, Mr. Panda wants to find a simple cycle with minmal cost in the Pandaland. To clarify, a simple cycle is a path which starts and ends on the same city and visits each road at most once. 
The cost of a cycle is the sum of the costs of all the roads it contains. 

Input

The first line of the input gives the number of test cases, T. T test cases follow. 
Each test case begins with an integer M. 
Following M lines discribes roads in Pandaland. 
Each line has 5 integers x1,y1,x2,y2,x1,y1,x2,y2, w, representing there is a road with cost w connecting the cities on (x1,y1)(x1,y1) and (x2,y2).(x2,y2). 

Output

For each test case, output one line containing Case #x: y, where x is the test case number (starting from 1) and y is the cost Mr. Panda wants to know. 
If there is no cycles in the map, y is 0. 

limits


∙1≤T≤50.∙1≤T≤50. 
∙1≤m≤4000.∙1≤m≤4000. 
∙−10000≤xi,yi≤10000.∙−10000≤xi,yi≤10000. 
∙1≤w≤105.∙1≤w≤105. 

Sample Input

2
5
0 0 0 1 2
0 0 1 0 2
0 1 1 1 2
1 0 1 1 2
1 0 0 1 5
9
1 1 3 1 1
1 1 1 3 2
3 1 3 3 2
1 3 3 3 1
1 1 2 2 2
2 2 3 3 3
3 1 2 2 1
2 2 1 3 2
4 1 5 1 4

Sample Output

Case #1: 8
Case #2: 4

题意:题目就是要找一个最小环   ,可枚举每一条边(最小环至少由3个点构成,枚举每一条边,计算该边从起点到终点且不经过该直达边的最短路,再加上该条直达边,这就构成了一个环,之后取最小值即可)(该方法暴力些,其他博客有更好的做法,但我觉得该方法较容易理解)

#include<iostream>
#include<cstring>
#include<map>
#include<queue>
#include<stdio.h>
using namespace std;
typedef pair<int,int>P;
map<P,int>mp;           //用map来存点(P是一个坐标,int是一个点的编号)
const int INF=0x3f3f3f3f;
const int maxn=4010;
int head[maxn<<1],dis[maxn<<1],vis[maxn<<1]; //总共4000条边,但是最多不过8000个点
int cnt,tol,minn;
struct Edge
{
    int v,w,next;
}e[maxn<<1];
struct node
{
    int u,v,w;
}a[maxn];           //用来存取每一条边
void Init()         //初始化
{
    mp.clear();
    cnt=1;
    tol=1;
    memset(head,-1,sizeof(head));
}
void add(int u,int v,int w)     //前向星
{
    e[cnt].v=v;
    e[cnt].w=w;
    e[cnt].next=head[u];
    head[u]=cnt++;
}
void Dijkstra(int s,int t,int ww)  //从s到t的最短路(不经过s->t这条直达边)
{
    memset(dis,INF,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[s]=0;
    priority_queue<P,vector<P>,greater<P> >que;
    que.push(P(0,s));           //0为最短距离,s为定点编号
    while(!que.empty())
    {
        P p=que.top();
        que.pop();
        if(p.first+ww>minn)   //如果该点的最短距离加上s->t这条直达边的权值
            break;            //大于了记录答案的minn,就不算。
        int u=p.second;
        if(vis[u])
            continue;
        vis[u]=1;
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            int v=e[i].v;
            int w=e[i].w;
            if((u==s&&v==t)||(u==t&&v==s))   //不经过s->t这条直达边(双向边).(其实不加后面的也能过)
                continue;
            if(!vis[v]&&dis[v]>dis[u]+w)    //更新
            {
                dis[v]=dis[u]+w;
                que.push(P(dis[v],v));
            }

        }
    }
}
int main()
{
    int t,k=1,m;
    cin>>t;
    while(t--)
    {
        Init();
        cin>>m;
        for(int i=1;i<=m;i++)
        {
            int x1,y1,x2,y2,w;
            cin>>x1>>y1>>x2>>y2>>w;
            if(!mp[P(x1,y1)])
                mp[P(x1,y1)]=tol++;  //用tol从1开始为每一个新出现的点编号
            if(!mp[P(x2,y2)])
                mp[P(x2,y2)]=tol++;
            int u=mp[P(x1,y1)];       //转换成编号之间的关系
            int v=mp[P(x2,y2)];
            add(u,v,w);
            add(v,u,w);
            a[i].u=u,a[i].v=v,a[i].w=w;//存边枚举
        }
        minn=INF;
        for(int i=1;i<=m;i++)   //枚举
        {
            Dijkstra(a[i].u,a[i].v,a[i].w);
            minn=min(minn,dis[a[i].v]+a[i].w);
        }
        printf("Case #%d: %d\n",k++,minn==INF?0:minn);
    }
    return 0;
}

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值