• Pandaland HDU


    题意:

    给出一个二维平面上的 (m) 条边和边的端点的坐标,求出图的最小环的长度。
    数据范围:
    (1≤T≤50)
    (1≤m≤4000)
    (−10000≤x_i,y_i≤10000)
    (1≤w≤10^5)

    解法1:(暴力+ (dijsktra)剪枝)

      删边,跑 (m)(dijsktra) ,同时注意剪枝,对于当前队列中最小的长度,如果已经比答案要大,肯定不行。
    一开始觉得这样做肯定超时,但看到网上的题解很多都是这做的,于是试了试。外加快读,链式前向星来优化,跑了 (343ms),有点惊讶。
    代码:

    #include <bits/stdc++.h>
    #define pb push_back
    #define inf 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> P;
    const int M=4e3+5;
    map<int,map<int,int> >mp;
    struct node
    {
        int from,to,val,next;
    }edge[M<<2];
    int dis[M<<1],head[M<<1];
    priority_queue<P,vector<P>,greater<P> >que;
    int ans,cot;
    void init()
    {
        memset(head,-1,sizeof(head));
        cot=1;
    }
    void addedge(int from,int to,int w)
    {
        edge[cot].from=from;
        edge[cot].to=to;
        edge[cot].val=w;
        edge[cot].next=head[from];
        head[from]=cot++;
    }
    void read(int &x)
    {
        x=0;
        int f=1;
        char ch=getchar();
        while(!isdigit(ch))
        {
            if(ch=='-')
                f=-1;
            ch=getchar();
        }
        while(isdigit(ch))
        {
            x=(x<<3)+(x<<1)+ch-'0';
            ch=getchar();
        }
        x*=f;
    }
    int dij(int s,int t,int w)
    {
        while(!que.empty())
            que.pop();
        que.push(make_pair(0,s));
        dis[s]=0;
        while(!que.empty())
        {
            P now=que.top();
            que.pop();
            if(now.first+w>ans)
                return inf;
            if(dis[now.second]<now.first)
                continue;
            if(now.second==t)//不加会t,加了后:343ms
                return dis[t];
            for(int i=head[now.second];i!=-1;i=edge[i].next)
            {
                node tmp=edge[i];
                if(tmp.val>=inf)
                    continue;
                if(dis[tmp.to]>now.first+tmp.val)
                {
                    dis[tmp.to]=now.first+tmp.val;
                    que.push(make_pair(dis[tmp.to],tmp.to));
                }
            }
        }
        return dis[t];
    }
    int main()
    {
        int t,cnt=0,m;
        read(t);
        while(t--)
        {
            init();
            read(m);
            mp.clear();
            int a,b,c,d,e;
            int num=0;
            ans=inf;
            for(int i=1;i<=m;i++)
            {
                read(a),read(b),read(c),read(d),read(e);
                if(mp[a][b]==0)
                    mp[a][b]=++num;
                if(mp[c][d]==0)
                    mp[c][d]=++num;
                addedge(mp[a][b],mp[c][d],e);
                addedge(mp[c][d],mp[a][b],e);
            }
            for(int i=1;i<cot;i+=2)
            {
                int tv=edge[i].val;
                edge[i].val=inf;
                edge[i+1].val=inf;
                fill(dis+1,dis+num+1,inf);
                int res=dij(edge[i].from,edge[i].to,tv);
                ans=min(ans,res+tv);
                edge[i].val=tv;
                edge[i+1].val=tv;
            }
            printf("Case #%d: ",++cnt);
            if(ans==inf)
                printf("0
    ");
            else
                printf("%d
    ",ans);
        }
        return 0;
    }
    
    

    解法2:(MST+LCA)

    最短的环除去一条边后一定是在这个图的最小生成树上
    可以通过枚举不在树上的边,求树上这条边的两点间距离,加上边的权值并取个最小值即可
    注意:题目给的图可能有多个联通块
    复杂度:(O(nlogn))
    用了 (78ms),因为(kruscal)忘记排序,用(lca)求树上两点间距离,公共祖先忘 (*2)(wa) 了两次,ε=(´ο`*)))唉。

    #include <bits/stdc++.h>
    #define pb push_back
    using namespace std;
    typedef pair<int,int> P;
    const int inf=0x3f3f3f3f;
    const int N=8e3+5;
    const int mak=16;
    struct edge
    {
        int from,to,val;
        bool operator < (const edge b)const
        {
            return val<b.val;
        }
    };
    vector<edge>e,s;
    vector<P>pic[N];
    map<int,map<int,int> >mp;
    int fa[N],par[N][mak],depth[N],wt[N],vis[N];
    int Find(int x)
    {
        if(x!=fa[x])
            return fa[x]=Find(fa[x]);
        else
            return x;
    }
    void kruscal(int n)
    {
        int cnt=0,i;
        s.clear();
        for(int i=1;i<=n;i++)
            pic[i].clear();
        sort(e.begin(),e.end());//注意排序
        for(i=0;i<e.size();i++)
        {
            int a=e[i].from;
            int b=e[i].to;
            int ta=Find(a);
            int tb=Find(b);
            if(ta!=tb)
            {
                fa[ta]=tb;
                pic[a].pb(make_pair(e[i].val,b));
                pic[b].pb(make_pair(e[i].val,a));
                cnt++;
            }
            else
                s.pb(e[i]);
            if(cnt==n-1)
                break;
        }
        for(i=i+1;i<e.size();i++)
            s.pb(e[i]);
    }
    void dfs(int v,int p,int w,int d,int cnt)
    {
        par[v][0]=p;
        depth[v]=d;
        wt[v]=w;
        vis[v]=cnt;
        for(int i=0;i<pic[v].size();i++)
        {
            P u=pic[v][i];
            if(u.second!=p)
                dfs(u.second,v,w+u.first,d+1,cnt);
        }
    }
    void init(int n,int &cnt)
    {
        fill(vis+1,vis+1+n,-1);
        cnt=0;//树的个数
        for(int i=1;i<=n;i++)
        {
            if(vis[i]==-1)
                dfs(i,-1,0,0,++cnt);
        }
        for(int k=0;k+1<mak;k++)
        {
            for(int i=1;i<=n;i++)
            {
                if(par[i][k]==-1)
                    par[i][k+1]=-1;
                else
                    par[i][k+1]=par[par[i][k]][k];
            }
        }
    }
    int lca(int u,int v)
    {
        if(vis[u]!=vis[v])//不在同一棵树
            return -1;
        if(depth[u]>depth[v])
            swap(u,v);
        for(int k=0;k<mak;k++)
        {
            if(((depth[v]-depth[u])>>k)&1)
                v=par[v][k];
        }
        if(u==v)
            return u;
        for(int k=mak-1;k>=0;k--)
        {
            if(par[u][k]!=par[v][k])
            {
                u=par[u][k];
                v=par[v][k];
            }
        }
        return par[u][0];
    }
    int solve(int cnt)
    {
        int res=inf;
        for(int i=0;i<s.size();i++)
        {
            int p=lca(s[i].from,s[i].to);
            if(p==-1)
                continue;
            res=min(res,s[i].val+wt[s[i].from]+wt[s[i].to]-2*wt[p]);//注意*2
        }
        return res;
    }
    int main()
    {
        int t,m,cot=0;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d",&m);
            mp.clear();
            e.clear();
            int num=0;
            int a,b,c,d,f;
            for(int i=1;i<=m;i++)
            {
                scanf("%d%d%d%d%d",&a,&b,&c,&d,&f);
                if(mp[a][b]==0)
                    mp[a][b]=++num;
                if(mp[c][d]==0)
                    mp[c][d]=++num;
                e.pb(edge{mp[a][b],mp[c][d],f});
            }
            int cnt=0;
            for(int i=1;i<=num;i++)
                fa[i]=i;
            kruscal(num);
            init(num,cnt);//cout<<"cnt="<<cnt<<endl;
            int ans=solve(cnt);
            if(ans==inf)
                ans=0;
            printf("Case #%d: %d
    ",++cot,ans);
        }
        return 0;
    }
    
    
  • 相关阅读:
    02---控制移动底座8
    02---控制移动底座7
    02---控制移动底座6
    02---控制移动底座5
    第四章输入/输出(I/O)4.2PCL中I/O模块及类介绍
    第四章输入/输出(I/O)4.1I/O涉及的设备及相关概念简介
    1.6 opencv视频操作基础
    1.5快速上手OpenCV图像处理
    02---控制移动底座4
    函数cvtColor
  • 原文地址:https://www.cnblogs.com/1024-xzx/p/12514190.html
Copyright © 2020-2023  润新知