zoukankan      html  css  js  c++  java
  • 图论

    图论

    最小环

    [CF1325E]数论+最小环

    一个数最多只有7个因子,意味着它是(a*a*b)或者(a*b)

    给定一个序列,每个数都最多只有7个因子,需要找到最短序列的长度,使得序列元素的乘积是完全平方数,且(a_i leq 10^6)

    思路:如果是(a*a),则答案为1

    ​ 如果是(a*a*b),把它变成(b*1),建一条(b)(1)的连边

    ​ 如果是(a*b),建一条(b)(a)的连边

    ​ (去重)

    ​ 找到最小环

    ​ 在考虑直接用最小环会超时

    ​ 发现如果有一个这样的序列,那么一定有一个点,小于(sqrt{10^6})

    ​ 那么只要枚举这1000个点即可(其实是小于1000的质数)

    ​ 注意:这题保证了至多有两个质因子

    ​ (From God Yan)

    注意这个数字分解的方法和最小环的求解

    第一份代码:大概在1500ms左右

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 100;
    const int inf = 0x3f3f3f3f;
    int a[maxn];
    int p[maxn];
    long long dis[maxn];
    vector<int> v, e[maxn];
    void init() {
        for (int i = maxn - 1; i >= 2;i--) {
            for (int j = i; j < maxn;j+=i) {
                p[j] = i;
            }
        }
    }
    int main() {
        int n;
        scanf("%d", &n);
        init();
        for(int i=1;i<=n;i++) {
            int x;scanf("%d",&x);
            int a = 1, b = 1;
            while(x!=1) {
                int t = p[x];
                if(x%(t*t)==0) {
                    x /= (t * t);
                }
                else {
                    x /= t;
                    if(a==1)
                        a = t;
                    else
                        b = t;
                }
            }
            e[a].push_back(b);
            e[b].push_back(a);
            v.push_back(a);
            v.push_back(b);
        }
        sort(v.begin(), v.end());
        int sz = unique(v.begin(), v.end())-v.begin();
        long long ans = inf;
        for(int x:v) {
            if(x>1000)
                break;
            queue<int> q;
            for (int i = 0; i < sz;i++) {
                dis[v[i]] = inf;
            }
            dis[x] = 0;
            q.push(x);
            while(!q.empty()) {
                int t = q.front();
                q.pop();
                for(int to:e[t]) {
                    if(dis[to]>dis[t]+1) {
                        dis[to] = dis[t] + 1;
                        q.push(to);
                    }
                    else if(dis[to]>=dis[t]) {
                        ans = min(ans, dis[to] + dis[t] + 1);
                    }
                }
            }
        }
    
        if(ans>=inf) {
            cout << -1 << endl;
        }
        else {
            cout << ans << endl;
        }
    }
    

    第二份代码:187ms

    1.首先

     if(dis[to]+dis[t]>=ans) continue;
    

    这一行剪枝可以优化一倍左右

    2.所有节点都是质因子且没有重边

    但是要注意两个特判

    3.也可以把去重的那一部分删掉,时间大概是320ms

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 100;
    const int inf = 0x3f3f3f3f;
    int a[maxn];
    int p[maxn];
    long long dis[maxn];
    vector<int> v, e[maxn];
    int pm[maxn],pid[maxn];
    int ptop;
    void init() {
        int n = maxn - 1;
        p[0] = 1;
        pm[1] = 1;
        pid[1] = 0;
        for(int i = 2; i <= n; ++i) {
            if(!pm[i]) {
                p[++ptop] = i;//新增一个质数
                pm[i] = i;//质数的因子是自己
                pid[i] = ptop;//这个质数的序号
            }
            for(int j = 1; j <= ptop; ++j) {
                int t = i * p[j];
                if(t > n)
                    break;
                pm[t] = p[j];
                if(i % p[j] == 0)
                    break;
            }
        }
    }
    int fj(int x) {
        int d = 1;
        while(x > 1) {
            int p = pm[x];
            x /= p;
            if(d % p == 0) {
                d /= p;
                continue;
            }
            d *= p;
        }
        return d;
    }
    int main() {
        int n;
        scanf("%d", &n);
        init();
        for(int i=1;i<=n;i++) {
            scanf("%d", &a[i]);
            a[i] = fj(a[i]);
        }
        sort(a + 1, a + 1 + n);
        int m = unique(a + 1, a + 1 + n) - (a + 1);
        if(a[1]==1) {
            cout << 1 << endl;
            return 0;
        }
        if(m<n){
            cout << 2 << endl;
            return 0;
        }
        for (int i = 1;i<=m;i++) {
            int x = pid[pm[a[i]]], y = pid[pm[a[i] / pm[a[i]]]];
            e[x].push_back(y);
            e[y].push_back(x);
        }
        long long ans = inf;
        for (int i = 0; i < ptop, p[i] <= 1000;i++) {
            int x = pid[p[i]];
            queue<int> q;
            for (int i = 0; i < ptop;i++) {
                dis[i] = inf;
            }
            dis[x] = 0;
            q.push(x);
            while(!q.empty()) {
                int t = q.front();
                q.pop();
                for(int to:e[t]) {
                    if(dis[to]>dis[t]+1) {
                        dis[to] = dis[t] + 1;
                        if(dis[to]+dis[t]>=ans)
                            continue;
                        q.push(to);
                    }
                    else if(dis[to]>=dis[t]) {
                        ans = min(ans, dis[to] + dis[t] + 1);
                    }
                }
            }
        }
        if(ans>=inf) {
            cout << -1 << endl;
        }
        else {
            cout << ans << endl;
        }
    }
    

    [CF1190E] Matching vs Independent Set 图匹配

    https://codeforces.com/contest/1199/problem/E

    给定一个3*n个点m条边的简单无向图,要求在这个图里找出一个有n条边的独立边集

    或者找出一个有n个点的独立点集,并且输出答案

    #include <bits/stdc++.h>
    #include<stdint.h>
    #define int long long
    #define scan(n) scanf("%lld", &(n))
    #define scann(n, m) scanf("%lld%lld", &(n), &(m))
    #define scannn(a, b, c) scanf("%lld%lld%lld", &(a), &(b), &(c))
    #define prin(n) printf("%lld", (n))
    #define pb push_back
    #define mp make_pair
    #define ms(a) memset(a, 0, sizeof(a))
    #define fo(i, a, b) for (int i = (a); i <= (b); i++)
    #define ro(i, a, b) for (int i = (a); i >= (b); i--)
    const int inf = 0x3f3f3f3f;
    using namespace std;
    const int maxn = 3e5+100;
    int n,m;
    int u[maxn],v[maxn];
    int vis[maxn];
    int32_t main() {
        int T;scan(T);
        while(T--){
            scann(n,m);
            fo(i,1,3*n)vis[i]=0;
            vector<int>edge_ans;
            fo(i,1,m){
                int u,v;scann(u,v);
                if(vis[u]||vis[v])continue;
                vis[u]=1,vis[v]=1;
                edge_ans.pb(i);
            }
            if(edge_ans.size()>=n){
                printf("Matching
    ");
                fo(i,0,n-1){
                    printf("%lld ",edge_ans[i]);
                }
            }
            else{
                printf("IndSet
    ");
                int cnt=0;
                fo(i,1,3*n){
                    if(cnt>=n)break;
                    if(!vis[i])printf("%lld ",i),cnt++;
                }
            }
            printf("
    ");
        }
        return 0;
    }
    

    Distance in Tree

    题目链接


    DFS

    [CF977E] dfs判环

    187ms 用dfs找连通块,并且需要环上的每个点的度为2

    #include<bits/stdc++.h>
    
    using namespace std;
    const int maxn = 2e5 + 5;
    
    int vis[maxn];
    int ans, f;
    vector<int> e[maxn];
    
    void dfs(int u) {   //遍历每个联通块
        vis[u] = 1;
        if(e[u].size()!=2)
            f = 1;
        for(int v : e[u]) {
            if(!vis[v])
                dfs(v);
        }
    }
    
    int main() {
        int n, m;
        scanf("%d%d",&n,&m);
        for (int i = 1; i <= m;i++) {
            int u,v;
            scanf("%d%d",&u,&v);
            e[v].push_back(u);
            e[u].push_back(v);
        }
        for(int i=1;i<=n;i++) {
            f = 0;
            if(!vis[i]) {
                dfs(i);
                if(f==0)ans++;
            }
        }
        printf("%d
    ", ans);
    }
    

    93ms 并查集

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 2e5 + 5;
    
    int f[maxn];
    int d[maxn];
    
    struct edge{
        int u, v;
    }e[maxn];
    
    int find(int x) {
        return f[x] == x ? x : f[x] = find(f[x]);
    } 
    
    int main() {
        int n,m;scanf("%d%d",&n,&m);
        for(int i=0;i<=n;i++)
            f[i] = i;
        for(int i=1;i<=m;i++) {
            scanf("%d%d", &e[i].u, &e[i].v);
            d[e[i].u]++;
            d[e[i].v]++;
        }
        int ans = 0;
        for(int i=1;i<=m;i++) {
            if(d[e[i].u]==2&&d[e[i].v]==2) {
                int a = find(e[i].u);
                int b = find(e[i].v);
                if(a==b)
                    ans++;
                else if(a<b)
                    f[b] = a;
                else
                    f[a] = b;
            }
        }
        cout << ans << endl;
    }
    

    Counting cliques DFS

    include <bits/stdc++.h>
    include<stdint.h>
    using namespace std;
    define int long long
    define scan(n) scanf("%lld", &(n))
    define scann(n, m) scanf("%lld%lld", &(n), &(m))
    define scannn(a, b, c) scanf("%lld%lld%lld", &(a), &(b), &(c))
    define pb push_back
    define fo(i, a, b) for (int i = (a); i <= (b); i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 2e5+100;
    int n,m,s,x,y,pre[20],e120,ans,tot,head[120];
    struct node{
        int v,nxt;
    }a[1024];
    void add(int u,int v){
        tot++;
        a[tot].v=v;
        a[tot].nxt=head[u];
        head[u]=tot;
    }
    void dfs(int u,int step){
        pre[step]=u;
        if(step==s){ans++;return;}
        for(int j=head[u];~j;j=a[j].nxt){
            int x=a[j].v;
            int f=1;
            fo(i,1,step){
                if(epre[i]==0){f=0;break;}
            }
            if(f){
                step++;
                dfs(x,step);
                step--;
            }
        }
        return;
    }
    int32_t main() {
        int T;scan(T);
        while(T--){
            scannn(n,m,s);
            fo(i,0,15)pre[i]=0;
            fo(i,0,105)fo(j,0,105)ei=0;
            fo(i,0,105)head[i]=-1;
            ans=0,tot=0;
            fo(i,1,m){
                scann(x,y);
                if(x>y)swap(x,y);
                ex=1;add(x,y);
            }
            fo(i,1,n)dfs(i,1);
            printf("%lld
    ",ans);
        }
        return 0;
    }
    

    BFS

    矩阵距离

    https://ac.nowcoder.com/acm/contest/1017/B

    01矩阵,求每个0最近的1的曼哈顿距离

    直接将所有1点加入队列即可

    这样每次都会更新同一深度的所有0

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1000+5;
    int dx[4] = {0, 0, 1, -1}, dy[4] = {1, -1, 0, 0};
    char s[maxn][maxn];
    int d[maxn][maxn];
    int n, m;
    struct node{
        int x, y;
    };
    queue<node> q;
    bool ok(int x,int y) {
        if(x>n||y>m||x<1||y<1)
            return false;
        return true;
    }
    
    int main() {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n;i++) {
            scanf("%s", s[i] + 1);
        }
        for (int i = 1; i <= n;i++) {
            for (int j = 1;j<=m;j++) {
                if(s[i][j]=='0')
                    d[i][j] = -1;
                else
                    q.push((node){i, j});
            }
        }
        while(!q.empty()) {
            node t = q.front();
            q.pop();
            int x = t.x;
            int y = t.y;
            for (int i = 0; i < 4;i++) {
                int xx = x + dx[i];
                int yy = y + dy[i];
                if(!ok(xx,yy))
                    continue;
                if(d[xx][yy]==-1) {
                    d[xx][yy] = d[x][y] + 1;
                    q.push((node){xx, yy});
                }
            }
        }
        for (int i = 1; i <= n;i++) {
            for (int j = 1; j <= m;j++) {
                printf("%d ", d[i][j]);
            }
            printf("
    ");
        }
    }
    
  • 相关阅读:
    词云图value传递数据不显示(已解决)
    中文分词并将结果存入数据库
    《浪潮之巅》阅读笔记(一)
    亿信BI——维度转换组件使用
    SyntaxError: NonUTF8 code starting with '\xef' in file(已解决)
    AJAX——POST请求
    Ajax前后端交互——后端接收前端页面变量
    Ajax——Get请求
    《浪潮之巅》阅读笔记(二)
    谷粒商城分布式基础(十)—— 商品服务API—新增商品 & 商品管理
  • 原文地址:https://www.cnblogs.com/guaguastandup/p/12585288.html
Copyright © 2011-2022 走看看