zoukankan      html  css  js  c++  java
  • 第三次模拟赛 订正题解

    这次考试是一个图论专练,从海亮回来图论已经搞了好几个月了,感觉有些问题的思想还是要好好揣摩一下,理解思路才能知道怎么做;

    第一题:

    第一遍没看见有向图,建了个图跑了个tarjan,后来发现读错题,我们来看一下谜一样的水数据,这O(N*M)的复杂都能过;

    随便写一个dfs吧,当前点遍历到的点的个数+1,如果遍历N个点,那么满足条件,记录下来,没什么可说的了;

    然后数据没让我失望,A了;

    #include<bits/stdc++.h>
    using namespace std;
    #define N 500010
    template<typename T>inline void read(T &x)
    {
        x=0;T f=1,ch=getchar();
        while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getchar();}
        while(isdigit(ch))  {x=(x<<1)+(x<<3)+(ch^48);  ch=getchar();}
        x*=f;
    }
    
    int n,m,x,y,tot,cnt,num,root,dfn[N],low[N],ans[N],v[N],lin[N];
    
    struct gg {
        int y,next;
    }a[N<<1];
    
    inline void add(int x,int y) {
        a[++tot].y=y;
        a[tot].next=lin[x];
        lin[x]=tot;
    }
    
    void dfs(int x) {
        for(int i=lin[x];i;i=a[i].next) 
            if(!v[a[i].y])
                ++cnt,v[a[i].y]=1,dfs(a[i].y);
    }
    
    int main() {
        freopen("flow.in","r",stdin);
        freopen("flow.out","w",stdout);
        read(n); read(m);
        for(int i=1,a,b;i<=m;++i)
            read(a),read(b),add(a, b);
        int k=0;
        for(int i=1;i<=n;++i) {
            memset(v,0,sizeof(v)); 
            cnt=1,v[i]=1;
            dfs(i); 
            if(cnt==n) ans[++k]=i;
        }
        if(!k) {
            putchar('0'); 
            return 0;
         }
        printf("%d
    ",k);
        for(int i=1;i<=k;++i) printf("%d ",ans[i]);
        return 0;
    }
    View Code

    第二题:

    我们来简化一下题意哈:

    每次选择两个点异或起来,再删除一个直至剩一个点,并且保证异或和最大;

    刚拿到题:以为是个trie树,正准备写,可是我不会怎么处理每次删除哪一个会更优;

    后来想了想,是个最大生成树,然后每两个点之间的权值是异或值,跑一个Prim或者Kruskal,考场上sb的推翻自己以为是基于点,我非得写Prim;

    数据还是没让人失望,让我这个sbA了;

    那没事,我现在补齐两种做法;

    Prim:

    #include<bits/stdc++.h>
    using namespace std;
    #define N 2500
    #define ll long long
    template<typename T>inline void read(T &x)
    {
        x=0;T f=1,ch=getchar();
        while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getchar();}
        while(isdigit(ch))  {x=(x<<1)+(x<<3)+(ch^48);  ch=getchar();}
        x*=f;
    }
    ll ans=0;
    int n,a[N],Map[N][N],dis[N],vis[N];
    inline void Prim_X() {
        vis[1]=1;
        for(int i=1;i<=n;i++) dis[i]=Map[1][i];
        for(int i=1;i<n;i++) {
            int y=0;
            for(int j=1;j<=n;j++) 
                if(!vis[j]&&dis[j]>dis[y])
                    y=j;
            ans+=dis[y];
            vis[y]=1;    
            for(int j=1;j<=n;j++) {
                if(!vis[j]) {
                    dis[j]=max(dis[j],Map[y][j]);
                }
            }
        }
    }
    
    int main() {
        freopen("bull.in","r",stdin);
        freopen("bull.out","w",stdout);
        read(n);
        for(int i=1;i<=n;i++) 
            read(a[i]);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++) 
                Map[i][j]=a[i]^a[j];
        Prim_X();
        cout<<ans<<endl;
        return 0;
    }
    View Code

    Kruskal:

    #include<bits/stdc++.h>
    using namespace std;
    #define N 50010
    int n,k,tot,h[N],father[N];
    long long ans;
    template<typename T>inline void read(T &x)
    {
        x=0;T f=1,ch=getchar();
        while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getchar();}
        while(isdigit(ch))  {x=(x<<1)+(x<<3)+(ch^48);  ch=getchar();}
        x*=f;
    }
    
    struct gg {
        int x,y;
        long long v;
    }a[N<<1];
    
    inline int find(int x) {
        return father[x]==x?x:father[x]=find(father[x]);
    }
    
    bool mycmp(gg x,gg y) {
        return x.v>y.v;
    }
    
    int main() {
        read(n);
        for(int i=1;i<=n;i++) {
            father[i]=i; read(h[i]);
            for(int j=1;j<i;j++) {
                a[++tot].x=i;
                a[tot].y=j;
                a[tot].v=h[i]^h[j];
            }
        }
        sort(a+1,a+tot+1,mycmp);
        k=0;
        for(int i=1;i<=tot;i++) {
            int x=find(a[i].x),y=find(a[i].y);
            if(x==y) continue;
            father[y]=x;
            ans+=a[i].v;
            k++;
            if(k==n-1) break;
        }
        cout<<ans<<endl;
        return 0;
    }
    View Code

    第三题:

    re了一个点,? 。跑N边spfa的人都过了,;

    我们往常写的都是一对多的spfa,那么今天写一个多对一的spfa,反向建图;

    对于每个点我们要求出这个点到点X再回来的最短路,

    点X到这个点的最短路只需要跑一遍以点X为源点的最短路就行了,

    但是每个点到点X的最短路怎么求呢?把边反向之后再跑一遍以点X为源点的最短路就行了。

    代码;考场写的代码太丑了,所以又写了一遍;

    #include<bits/stdc++.h>
    using namespace std;
    #define inf 0x3f3f3f
    #define N 50010
    template<typename T>inline void read(T &x)
    {
        x=0;T f=1,ch=getchar();
        while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getchar();}
        while(isdigit(ch))  {x=(x<<1)+(x<<3)+(ch^48);  ch=getchar();}
        x*=f;
    }
    
    int n,m,s,tot,cnt,a,b,l,dis1[N],dis2[N],lin1[N],lin2[N],vis[N];
    
    struct gg {
        int x,y,v,next;
    }e1[N<<1],e2[N<<1];
    
    inline void add1(int x,int y,int v) {
        e1[++tot].y=y;
        e1[tot].next=lin1[x];
        e1[tot].v=v;
        lin1[x]=tot;
    }
    
    inline void add2(int x,int y,int v) {
        e2[++cnt].y=y;
        e2[cnt].next=lin2[x];
        e2[cnt].v=v;
        lin2[x]=cnt;
    }
    
    inline void spfa1() {
        memset(vis,0,sizeof(vis));
        queue<int> q;
        q.push(s);
        vis[s]=1;dis1[s]=0;
        while(!q.empty()) {
            int x=q.front();
            q.pop();
            vis[x]=0;
            for(int i=lin1[x];i!=0;i=e1[i].next) {
                if(dis1[x]+e1[i].v<dis1[e1[i].y]) {
                    dis1[e1[i].y]=dis1[x]+e1[i].v;
                    if(!vis[e1[i].y]) {
                        vis[e1[i].y]=1;
                        q.push(e1[i].y);
                    }
                }
            }
        }
    }
    
    inline void spfa2() {
        queue<int> q;
        memset(vis,0,sizeof(vis));
        q.push(s);
        vis[s]=1;dis2[s]=0;
        while(!q.empty()) {
            int x=q.front();
            q.pop();
            vis[x]=0;
            for(int i=lin2[x];i!=0;i=e2[i].next) {
                
                if(dis2[x]+e2[i].v<dis2[e2[i].y]) {
                    dis2[e2[i].y]=dis2[x]+e2[i].v;
                    if(!vis[e2[i].y]) {
                        vis[e2[i].y]=1;
                        q.push(e2[i].y);
                    }
                }
            }
        }
    }
    
    int main() {
        read(n); read(m); read(s);
        memset(dis1,127,sizeof(dis1));
        memset(dis2,127,sizeof(dis2));
        for(int i=1;i<=m;i++) {
            read(a);read(b);read(l);
            e1[i].y=b; e1[i].next=lin1[a]; lin1[a]=i; e1[i].v=l;
            e2[i].y=a; e2[i].next=lin2[b]; e2[i].v=l; lin2[b]=i;//反向建边; 
        }
        spfa1(); spfa2();
        int ans=0;
        for(int i=1;i<=n;i++)
            ans=max(ans,dis1[i]+dis2[i]);
        cout<<ans<<endl;
        return 0;
    }
    View Code

    分数:290分,另外10分献给sb的自己;

    本来计划最近复习图论,结果直接考了,最近计划复习图论考点,写写以前的经典题目,还要学搜索最近,加油!

  • 相关阅读:
    程序开发
    主方法
    日志
    node.js
    二维互换
    前台打断点
    具体的后台断点快捷键
    Jenkins
    断点
    循环
  • 原文地址:https://www.cnblogs.com/Tyouchie/p/11037842.html
Copyright © 2011-2022 走看看