• 模拟赛 最小环 题解


    求包含1号点的最小环。

    这个最小环一定是从1点的出边指向的点出发,再回到另一个1点的出边指向的点。

    这等价于1号点所有出边指向的点中,两两之间最短路+1号点到这两个点的距离的最小值。

    使用二进制拆分,分成两组点,分别向s,t连边,正反算两次最短路。

    时间复杂度 (O((n+m)log^2 n))

    二进制分组是很常用的思路。

    参考代码:

    #include <stdio.h>
    #include <queue>
    using namespace std;
    int fr[5010],ne[30010],inf=999999999;
    int v[30010],w[30010],bs=0,n;
    int jl[5010],sz[5010],cd1[5010],cd2[5010];
    bool bk[5010];
    void addb(int a,int b,int c)
    {
    	v[bs]=b;
    	w[bs]=c;
    	ne[bs]=fr[a];
    	fr[a]=bs;
    	bs+=1;
    }
    struct SJd               
    {                        
        int u,z;
    	SJd(){};
    	SJd(int Z,int U)
    	{
    		z=Z;
    		u=U;
    	}
    	bool operator<(const SJd&a)const
    	{
    		return z>a.z;
    	}
    };
    int dij(int S,int T)
    {
    	for(int i=1;i<=n;i++)
    	{
    		bk[i]=false;
    		jl[i]=inf;
    	}
    	jl[S]=0;
    	priority_queue<SJd> dl;
    	dl.push(SJd(0,S));
        while(!(dl.empty()))
        {
    		SJd	t=dl.top();
    		dl.pop();
    		if(bk[t.u])
    			continue;
    		bk[t.u]=true;
            for(int j=fr[t.u];j!=-1;j=ne[j])                  
            {      
    			if(v[j]==1)
    				continue;
                if(t.z+w[j]<jl[v[j]])                        
                { 
    				jl[v[j]]=t.z+w[j];
                    dl.push(SJd(jl[v[j]],v[j]));
                }
            }                                                
        }
    	return jl[T];
    }
    int main()
    {
    	freopen("B.in","r",stdin);
    	freopen("B.out","w",stdout);
    	int m,k=0,jg=inf;
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n+2;i++)
    		fr[i]=-1;
    	for(int i=0;i<m;i++)
    	{
    		int a,b,c,d;
    		scanf("%d%d%d%d",&a,&b,&c,&d);
    		addb(a,b,c);
    		addb(b,a,d);
    	}
    	for(int i=fr[1];i!=-1;i=ne[i])
    	{
    		sz[k]=v[i];
    		cd1[k]=w[i];
    		cd2[k]=w[i^1];
    		k+=1;
    	}
    	n+=2;
    	for(int i=16;i>=0;i--)
    	{
    		for(int j=0;j<k;j++)
    		{
    			if(j&(1<<i))
    			{
    				addb(n,sz[j],cd1[j]);
    				addb(sz[j],n,cd1[j]);
    			}
    			else
    			{
    				addb(n-1,sz[j],cd2[j]);
    				addb(sz[j],n-1,cd2[j]);
    			}
    		}
    		int rt=dij(n,n-1);
    		if(rt<jg)
    			jg=rt;
    		bs-=k*2;
    		for(int j=0;j<k;j++)
    			fr[sz[j]]=ne[fr[sz[j]]];
    		fr[n]=fr[n-1]=-1;
    		//
    		for(int j=0;j<k;j++)
    		{
    			if(!(j&(1<<i)))
    			{
    				addb(n,sz[j],cd1[j]);
    				addb(sz[j],n,cd1[j]);
    			}
    			else
    			{
    				addb(n-1,sz[j],cd2[j]);
    				addb(sz[j],n-1,cd2[j]);
    			}
    		}
    		rt=dij(n,n-1);
    		if(rt<jg)
    			jg=rt;
    		bs-=k*2;
    		for(int j=0;j<k;j++)
    			fr[sz[j]]=ne[fr[sz[j]]];
    		fr[n]=fr[n-1]=-1;
    	}
    	printf("%d",jg);
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    September 17th 2016 Week 38th Saturday
    【2016-09-16】UbuntuServer14.04或更高版本安装问题记录
    September 16th 2016 Week 38th Friday
    September 11th 2016 Week 38th Sunday
    September 12th 2016 Week 38th Monday
    September 10th 2016 Week 37th Saturday
    September 9th 2016 Week 37th Friday
    c++暂停
    八皇后问题
    ( 转转)Android初级开发第九讲--Intent最全用法(打开文件跳转页面等)
  • 原文地址:https://www.cnblogs.com/lnzwz/p/11246797.html
Copyright © 2020-2023  润新知