zoukankan      html  css  js  c++  java
  • DAY 7 上午

    一些图论的题目


    BZOJ 3445 Roadblock

    求出最短路,枚举每条边再跑一遍即可(科技为了我

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    int n,m;
    
    int head[105],cnt=1;
    struct edge
    {
        int dis,to,nxt;
    }edg[10005];
    
    inline void add(int u,int v,int w)
    {
        edg[++cnt].to=v;
        edg[cnt].dis=w;
        edg[cnt].nxt=head[u];
        head[u]=cnt;
        edg[++cnt].to=u;
        edg[cnt].dis=w;
        edg[cnt].nxt=head[v];
        head[v]=cnt;
    }
    
    ll diss[105];
    bool vis[105];
    int pre[105];
    ll qwq;
    ll ans;
    
    inline void dij()
    {
        priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > > q;
        q.push(make_pair(0,1));
        for(int i=1;i<=n;i++) diss[i]=99999999999;
        diss[1]=0;
        while(!q.empty())
        {
            int now=q.top().second;
            q.pop();
            if(vis[now]) continue;
            vis[now]=1;
            for(int i=head[now];i;i=edg[i].nxt)
            {
                int v=edg[i].to;
                if(diss[now]+edg[i].dis<diss[v])
                {
                    diss[v]=diss[now]+edg[i].dis;
                    q.push(make_pair(diss[v],v));
                    pre[v]=i;
                }
            }
        }
        qwq=diss[n];
    }
    
    inline void dijnew()
    {
        priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > > q;
        q.push(make_pair(0,1));
        for(int i=1;i<=n;i++) diss[i]=99999999999,vis[i]=0;
        diss[1]=0;
        while(!q.empty())
        {
            int now=q.top().second;
            q.pop();
            if(vis[now]) continue;
            vis[now]=1;
            for(int i=head[now];i;i=edg[i].nxt)
            {
                int v=edg[i].to;
                if(diss[now]+edg[i].dis<diss[v])
                {
                    diss[v]=diss[now]+edg[i].dis;
                    q.push(make_pair(diss[v],v));
                }
            }
        }
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1,u,v,w;i<=m;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
        }
        dij();
        for(int i=1;i<=n;i++)
        {
            int t=pre[i];
            edg[t].dis<<=1;edg[t^1].dis<<=1;
            dijnew();
            ans=max(ans,diss[n]);
            edg[t].dis>>=1;edg[t^1].dis>>=1;
        }
        cout<<ans-qwq;
    }

    建一个分层图

    原图在第一层

    第一层向第二层连有向边

    对于u-->v,从第一层的u点向第二层的v点连一条长度为0的边

    优于更新有可能用不到k次

    从上一层的点u到下一层的点u连一条长度为0的边,表示不用这次更新

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    int n,m,k;
    
    int head[210005],cnt;
    struct edge
    {
        int dis,to,nxt;
    }edg[4200005];
    
    inline void add(int u,int v,int w)
    {
        edg[++cnt].to=v;
        edg[cnt].dis=w;
        edg[cnt].nxt=head[u];
        head[u]=cnt;
    
    }
    
    ll diss[210005];
    bool vis[210005];
    ll ans;
    
    inline void dij()
    {
        priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > > q;
        q.push(make_pair(0,1));
        for(int i=1;i<=n*(k+1);i++) diss[i]=9999999999;
        diss[1]=0;
        while(!q.empty())
        {
            int now=q.top().second;
            q.pop();
            if(vis[now]) continue;
            vis[now]=1;
            for(int i=head[now];i;i=edg[i].nxt)
            {
                int v=edg[i].to;
                if(diss[now]+edg[i].dis<diss[v])
                {
                    diss[v]=diss[now]+edg[i].dis;
                    q.push(make_pair(diss[v],v));
                }
            }
        }
    }
    
    
    
    int main()
    {
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1,u,v,w;i<=m;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
            add(v,u,w);
            for(int j=1;j<=k;j++)
            {
                add(j*n+u,j*n+v,w);
                add(j*n+v,j*n+u,w);
                add((j-1)*n+u,j*n+v,0);
                add((j-1)*n+v,j*n+u,0);
            }  
        }
        dij();
        ll ans=diss[n];
        for(int i=1;i<=k;i++)
        {
            ans=min(ll(ans),diss[i*n+n]);
        }
        cout<<ans;
        
    }

    min(x3-x1,y3-y1)=x3-x1>=min(x2-x1,y2-y1)+min(x3-x2,y3-y2)

    按x轴排序,相邻的点建边,然后建O(n)条

    跑dij就行了

    小边越大,最大边越大

    最小边变大之后,最大边能选取的范围变小了,且有可能会变大

    固定最小边,最小化最大边
    并查集维护连通性

    先把最小边拿出来,看看能不能加进去,重复操作,直到s和t联通

    把最小边从大往小枚举

    每次新的边可用的时候,如果连通块正好联通就可以

    如果会出环,那么找到u和v之前的路径上最大的边

    对于枚举的最小边,看看最大边是谁

    1.二分答案

    所有长度<=mid的边属于部落内部

    >mid的边属于部落外部

    看看有多少个连通块

    如果连通块数比k多就可行

    2.kruscal

    n^2连边

    把部落看成连通块

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    int n,k;
    int fa[1005];
    int cnt;
    double ans;
    
    struct edge
    {
        int from,to;
        double dis;
    }edg[1000005];
    
    struct node
    {
        int x,y;
    }nod[1005];
    
    inline bool cmp(edge a,edge b)
    {
        return a.dis<b.dis;
    }
    
    inline int find(int x)
    {
        while(x!=fa[x]) x=fa[x]=fa[fa[x]];
        return x;
    }
    
    /*inline void kruscal()
    {
        int t=0;
        for(int i=1;i<=n;i++) fa[i]=i;
        for(int i=1;i<=cnt;i++)
        {
            if(t==n-k)
            {
                ans=edg[i+1].dis;
                return;
            }
            if(find(edg[i].to)!=find(edg[i].from))
            {
                fa[find(edg[i].to)]=find(edg[i].from);
                t++;
            }
        }
    
    }*/
    
    inline void kruscal()
    {
        int t=0;
        bool flag=0;
        for(int i=1;i<=n;i++) fa[i]=i;
        for(int i=1;i<=cnt;i++)
        {
            if(t==n-k)
            {
                flag=1;
            }
            if(find(edg[i].to)!=find(edg[i].from))
            {
                fa[find(edg[i].to)]=find(edg[i].from);
                t++;
                if(flag==1)
                {
                    ans=edg[i].dis;
                    return ;
                }
            }
            
        }
    
    }
    
    int main()
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++) scanf("%d%d",&nod[i].x,&nod[i].y);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<i;j++)
            {
                edg[++cnt].from=i;
                edg[cnt].to=j;
                edg[cnt].dis=sqrt((nod[i].x-nod[j].x)*(nod[i].x-nod[j].x)+(nod[i].y-nod[j].y)*(nod[i].y-nod[j].y));
            }
        }
        sort(edg+1,edg+1+cnt,cmp);
        kruscal();
        printf("%.2lf",ans);
    }

    选一条边表示两个点属于同一个连通块

    目标就是选若干条边使得图分成k个连通块,并且没有选中的边的最小值尽可能大

    kruscal选中n-k条边就停止

    知道了一个点的奇偶性就可以看出来它有没有

    1,1~2,1~3,...,1~n的奇偶性就可以知道所有的奇偶性

    前缀和任何一个可行的方案一定可以推出s1~sn

    如果我询问了l~r,则我可以知道s[r]-s[l-1]的奇偶性

    %2意义下加法就是异或

    有传递性

    如果我知道s[x]和s[y]奇偶相同,s[y]和s[z]奇偶相同,则s[x]和s[z]奇偶相同

    已经知道s[0]=0

    目的就是s[1]~s[n]的所有点和s[0]联通起来

    有n^2条边,n+1个点,跑最小生成树就行了

    贪心策略:在每一个点去往最近的加油站

    以所有加油站为源点跑多源最短路,顺便维护最初的源点,现在知道每一个加油站离他最近的源点

    可以看成在加油站之间的移动

    枚举原图的边,如果两点最近加油站不同,就连边

    对加油站跑最小生成树

    留下最短路图的公共部分

    留下有向边

    一定无环(DAG)

    求dag上最长路,拓扑+dp

    设a1是最小的,在模a1意义下一个数的所有取值只有0~a1-1

    而如果 k 是可被表示的,那么 k + a[1], k + 2 × a[1], . . . 都可被表示。故问题转化为求解每个位置最小可被表示数字。建a1个点

    x-->(x+aj)%ai(相当于每次+aj)

    就可以转移模数

    希望走的边的长度尽可能小

    大于这个东西就可以表示

    加边之后从零点跑单源最短路

    线形基

    给你若干个int,把他们抑或起来,最后异或出来的数是有限的

    发现原来的数是很冗余的,只需要其中某些数就可以达到原来的效果

    1 xor 2 = 3 1,2,3是线性相关的  或者说 1 xor 2 xor 3 = 0

    就是说保留两个就可以出来第三个

    线性基是拟阵

    遗传性,交换性

    每一个数分配权值

    给你一个集合

    找到一个子集使得它的权值最小并且是线性基

    怎么解释生成森林和线性基对应

    每一条边对应二进制

    当且仅当环异或起来是0

    k条边最短路

    具有结合律

    可以求出A^1,A^2,A^4...

    也可以快速幂

    O(n^3logn)

    应用:

    给你一张图,判断最小的负环

    求A^1,A^2,A^3...有没有负环,如果有的话就是最小的

    可以二分优化

    用倍增的思想往上跳

  • 相关阅读:
    ubuntu 启动 卡死在 clean ... file ... blocks
    realsense opencv example 运行时无显示退出
    realsense example 最简单编译
    python内置方法
    接口自动化测试框架
    git使用问题
    自动化测试工具原理
    四层协议网络传输
    字符串反转
    排除链接数性能瓶颈
  • 原文地址:https://www.cnblogs.com/lcezych/p/11348416.html
Copyright © 2011-2022 走看看