zoukankan      html  css  js  c++  java
  • CERC 2015 Juice Junctions


    原文链接:https://blog.csdn.net/a_forever_dream/java/article/details/103060734

    有一张图,每个点至多连三条边,每条边流量上限都是 1,设 f(x,y) 表示 x到 y 的最大流量,那么要你求出 、
    所有不同的两个点对的流量之和.

    input
    6 8
    1 3
    2 3
    4 1
    5 6
    2 6
    5 1
    6 4
    5 3
    output
    36

    因为每个点至多连三条边,所以 f(x,y) f(x,y)f(x,y) 的值只可能是 0,1,2,3 0,1,2,30,1,2,3。

    如果两点间不连通,那么就是 0

    如果两点不在一个边双里面但是连通,那么这两点间的路径显然有割点,所以就是 1

    那么怎么判断 2和 3呢?

    如果是 2 的话,那么说明两点间只有两条边不重复路径,那么如果删掉路径上的一条边,那么这两个点就不属于同一个边双了。

    所以我们可以尝试删掉图中的每一条边,然后每次都求一次边双,假如两个点一直存在于同一个边双,那么就是 3,否则是 2。

    怎么判断呢?我们可以将一个点呆过的所有边双的编号用哈希压成一个数,然后判断两点的哈希值是否相等即可。

    #include <cstdio>
    #include <cstring>
    #define maxn 3010
    
    int n,m;
    struct edge{int y,next;};
    edge e[maxn<<2];
    int first[maxn],len=1;
    void buildroad(int x,int y)
    {
    	e[++len]=(edge){y,first[x]};
    	first[x]=len;
    }
    int dfn[maxn],low[maxn],belong[maxn],block[maxn],id=0,cnt=0;
    int zhan[maxn],t=0;
    void dfs(int x,int from,int edg)
    {
    	dfn[x]=low[x]=++id;zhan[++t]=x;
    	for(int i=first[x];i;i=e[i].next)
    	{
    		if(i==(from^1)||i==edg||i==(edg^1))continue;
    		int y=e[i].y;
    		if(!dfn[y])
    		{
    			if(edg==-1)block[y]=block[x];
    			dfs(y,i,edg);
    			if(low[y]<low[x])low[x]=low[y];
    		}
    		else if(dfn[y]<low[x])low[x]=dfn[y];
    	}
    	if(dfn[x]==low[x])
    	{
    		cnt++; int xx;
    		do{
    			xx=zhan[t--];
    			belong[xx]=cnt;
    		}while(xx!=x);
    	}
    }
    void tarjan(int edg=0)
    {
    	memset(dfn,0,sizeof(dfn));
    	memset(low,0,sizeof(low));
    	memset(belong,0,sizeof(belong));id=cnt=0;
    	for(int i=1;i<=n;i++)
    	if(dfn[i]==0)dfs(i,-1,edg);
    }
    int ans[maxn][maxn];
    void work1()
    {
    	for(int i=1;i<=n;i++)
    	if(dfn[i]==0)block[i]=i,dfs(i,-1,-1);
    	for(int i=1;i<n;i++)
    	for(int j=i+1;j<=n;j++)
    	if(block[i]!=block[j])ans[i][j]=0;
    	else if(belong[i]!=belong[j])ans[i][j]=1;
    }
    int hash[maxn];
    #define mod 100000007
    void work2()
    {
    	for(int i=2;i<=len;i+=2)
    	{
    		tarjan(i);
    		for(int j=1;j<=n;j++)
    		hash[j]=(hash[j]*13+belong[j])%mod;
    	}
    	for(int i=1;i<n;i++)
    	for(int j=i+1;j<=n;j++)
    	if(ans[i][j]==-1)ans[i][j]=hash[i]==hash[j]?3:2;
    }
    void print()
    {
    	int tot=0;
    	for(int i=1;i<n;i++)
    	for(int j=i+1;j<=n;j++)
    	tot+=ans[i][j];
    	printf("%d",tot);
    }
    
    int main()
    {
    	scanf("%d %d",&n,&m);
    	for(int i=1,x,y;i<=m;i++)
    	scanf("%d %d",&x,&y),buildroad(x,y),buildroad(y,x);
    	memset(ans,-1,sizeof(ans));
    	work1();
    	work2();
    	print();
    }
    

      

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll unsigned long long
    using namespace std;
    inline int read()
    {
        int r,s=0,c;
        for(;!isdigit(c=getchar());s=c);
        for(r=c^48;isdigit(c=getchar());(r*=10)+=c^48);
        return s^45?r:-r;
    }
    const int N=3010,M=4510;
    const ll p=19491001;
    int n,m;
    struct edge
    {
        int to,next;
    }mem[M<<1];
    int head[N],cnt=1;
    inline void add(int u,int v)
    {
        mem[++cnt].next=head[u];
        mem[cnt].to=v;
        head[u]=cnt;
    }
    int fa[N],f1,f2;
    inline int getfa(int x)
    {
        if(fa[x]!=x)fa[x]=getfa(fa[x]);
        return fa[x];
    }
    int dfn[N],low[N],ti;
    int st[N],top;
    int dcc[N],co;
    bool vis[M<<1];
    ll d[N];
    void tarjan(int u,int no)
    {
        low[u]=dfn[u]=++ti;
        st[++top]=u;
        for(int i=head[u];i>0;i=mem[i].next)
        {
            if(vis[i])continue;
            if((i==no)||((i^1)==no))continue;
            int to=mem[i].to;
            if(!dfn[to])
            {
                vis[i]=vis[i^1]=1;
                tarjan(to,no);
                vis[i]=vis[i^1]=0;
                low[u]=min(low[u],low[to]);
            }
            else
                low[u]=min(low[u],dfn[to]);
        }
        if(low[u]==dfn[u])
        {
            dcc[u]=++co;
            while(st[top]!=u)
                dcc[st[top--]]=co;
            top--;
        }
    }
    inline void work()
    {
        for(int i=1;i<=n;i++)
            d[i]=1ll;
        for(int no=1;no<=m+1;no++)
        {
            memset(low,0,sizeof(low));
            memset(dfn,0,sizeof(dfn));
            ti=0,co=0,top=0;
            for(int i=1;i<=n;i++)
                if(!dfn[i])
                    tarjan(i,no<<1);
            for(int i=1;i<=n;i++)
                d[i]=d[i]*p+(ll)dcc[i];
        }
    }
    inline int calc(int u,int v)
    {
        f1=getfa(u),f2=getfa(v);
        if(f1!=f2)//不在一个集合内最大流为0 
            return 0;
        if(dcc[u]!=dcc[v])//不在一个dcc内最大流为1
            return 1;
        if(d[u]==d[v])//用hash判断每次的dcc是否完全相同 
            return 3;/*如果删掉任意一条边,u,v仍在同一个dcc内
        则u,v在同一个三联通分量内,即最大流为3*/
        return 2;//否则最大流为2  
    }
    int main()
    {
        n=read(),m=read();
        for(int i=1;i<=n;i++)
            fa[i]=i;
        int u,v;
        for(int i=1;i<=m;i++)
        {
            u=read(),v=read();
            add(u,v),add(v,u);
            f1=getfa(u),f2=getfa(v);
            if(f1!=f2)fa[f1]=f2;
        }
        work();
        int ans=0;
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
                ans+=calc(i,j);
        printf("%d
    ",ans);
        return 0;
    }
    

      

  • 相关阅读:
    夜神模拟器连接电脑
    Appium+python 多设备自动化测试
    appium+python 连接手机设备的yaml配置文件
    appium+python自动化测试连接设备
    Ansible 学习目录
    Python 时间处理
    获取本机网卡ip地址
    Ansible playbook 使用
    ansible hosts配置
    python os和sys模块使用
  • 原文地址:https://www.cnblogs.com/cutemush/p/12688373.html
Copyright © 2011-2022 走看看