zoukankan      html  css  js  c++  java
  • Codeforces Round #477 (rated, Div. 2, based on VK Cup 2018 Round 3) F 构造

    http://codeforces.com/contest/967/problem/F

    题目大意:

    有n个点,n*(n-1)/2条边的无向图,其中有m条路目前开启(即能走),剩下的都是关闭状态

    定义:从x走到y(即x->y)后,和x所连接的边的所有状态都反转(即开启->关闭,关闭->开启)

    问,从起点1走到终点n,最少需要经过几步,并且输出这个路径(如果存在多挑最短路径,输出任意一条)

    如果不存在,则输出-1

    思路:

    其实这道题第一眼看过去就是bfs,不过,由于每个状态都在改变,那要怎么利用这个bfs的特性呢?

    后来画了画图,你会发现,存在如下的问题。

    对于一个a+1个点,b条边的图(其中终点,即a+1这个点是没有边连向它)来说,如果b=a*(a-1)/2,那么,无论如何都是走不到a+1这个点的。

    所以,问题就转换成,如果b<a*(a-1)/2需要走几步。

    于是我们可以发现,在b<a*(a-1)/2的情况中,我们又可以找出bb=aa*(aa-1)/2的情况。 其中bb表示b的子集,aa表示a的子集

    于是不断剖析下去,最后只会得到两种情况

    第一种:

    a=3, b=2的情况(注,a=4才是终点,前面定义过了= =)

    图形:①->②->③

    即该情况步数是4步,即1->2->3->1->4

    第二种:

    a=4,  b=5的情况

    (= =)一共4个点,告诉你边,你自己画吧

    边为:

    1 2

    2 3

    3 4

    4 1

    1 3

    该情况步数是5

    当然,可能存在步数<=4的情况,即从1出发直接按照题目所给边走到终点,这个就不用我说了吧!!!(具体为什么的话,请自己利用上面的两种情况分析一下)

    所以根本不存在output中说的le6的情况

    对于前面两种情况中,步数=4的情况是容易解决的,关键就是步数=5的情况容易TLE(= =,退役一年没做题,脑子锈逗了,T了一天)

    首先我们可以发现步数=5的情况可以转移成——在删除起点1之后,步数=4的情况。

    因此,我们只需要找一个从1->u的情况,设u包含u下面所有的子节点(不包含1)个数位C,那么如果该集合的节点个数(包含u)< u的边数,那么就存在解

    解为1->u->v->z->u->n

    然而= =,楼主先暴力u,再暴力v,再暴力z,T死我了

    改成先暴力u,再暴力z,最后通过u、z找v就过了= =

    原因是,因为你会发现,v满足的条件比z满足的条件要少,所以v的剪枝比较少,因此先暴力v所要判断的节点数目会更多,因此不优秀

     (退役了以后做题是真的伤不起,还写得很麻烦= =,懒得优化了,自己看着办吧)

    //看看会不会爆int!数组会不会少了一维!
    //取物问题一定要小心先手胜利的条件
    #include <bits/stdc++.h>
    using namespace std;
    #pragma comment(linker,"/STACK:102400000,102400000")
    #define LL long long
    #define ALL(a) a.begin(), a.end()
    #define pb push_back
    #define mk make_pair
    #define fi first
    #define se second
    #define haha printf("haha
    ")
    const int maxn = 5e5 + 5;
    int n, m;
    vector<int> G[maxn];
    bool vis[maxn];
    int pre[maxn];
    
    bool bfs(int u){
        queue<pair<int, int> > que;
        que.push(mk(1, 0));
        memset(pre, -1, sizeof(pre));
        vis[1] = 1;
        while (!que.empty()){
            pair<int, int> p = que.front(); que.pop();
            int u = p.fi, step = p.se;
            //if (u == n) break;
            for (int i = 0; i < G[u].size(); i++){
                int v = G[u][i];
                if (vis[v]) continue;
                vis[v] = true;
                pre[v] = u;
                if (step + 1 <= 4){
                    que.push(mk(v, step+1));
                }
            }
        }
        while(!que.empty()) que.pop();
        if (pre[n] == -1) return false;
        int pos = n;
        vector<int> ans; ans.pb(pos);
        while (pre[pos] != -1){
            ans.pb(pre[pos]);
            pos = pre[pos];
        }
        reverse(ALL(ans));
        if (ans.size() > 5) return false;
        printf("%d
    ", ans.size()-1);
        for (int i = 0; i < ans.size(); i++)
            printf("%d ", ans[i]);
        cout << endl;
        return true;
    }
    
    void display(int a, int b, int  c, int d, int e, int f){
        printf("5
    %d %d %d %d %d %d
    ", a, b, c, d, e, f);
    }
    
    void bfs2(int x, vector<int> &cache){
        vis[x] = 1;
        queue<int> que;
        que.push(x);
        cache.pb(x);
        while (!que.empty()){
            int u = que.front(); que.pop();
            for (int i = 0; i < G[u].size(); i++){
                if (vis[G[u][i]] || u == 1)continue;
                vis[G[u][i]] = 1;
                que.push(G[u][i]);
                cache.pb(G[u][i]);
            }
        }
    }
    
    set<int> mys[maxn];
    int main(){
        cin >> n >> m;
        for (int i =1 ;i <= m; i++){
            int u,  v; scanf("%d%d", &u, &v);
            G[u].pb(v), G[v].pb(u);
            mys[u].insert(v); mys[v].insert(u);
        }
        if (m == 0) return puts("-1"), 0;
        if (n == 1) return printf("1
    1
    "), 0;
        //direct from 1 to n
        if (bfs(1)) return 0;
        memset(vis, 0, sizeof(vis));
        //other(just 4 steps)
    
        for (int i = 0; i < G[1].size(); i++){//the next point which connect to 1
            vis[G[1][i]] = 1;
        }
        for (int i = 0; i < G[1].size(); i++){
            int u = G[1][i];
            for (int j = 0; j < G[u].size(); j++){
                int v = G[u][j];
                if (v == 1 || vis[v]) continue;
                printf("4
    1 %d %d 1 %d
    ", u, v, n);
                return 0;
            }
        }
        //other(just 5 steps)
        //1->u->v->z->u->n
        memset(vis, 0, sizeof(vis));
        vector<int> cache;
        for (int i = 0; i < G[1].size(); i++){
            int u = G[1][i];
            if (vis[u]) continue;
            cache.clear();
            bfs2(u, cache);
            if (G[u].size() < cache.size()){
                for (int j = 0; j < cache.size(); j++){
                    u = cache[j];
                    if (!mys[u].count(1)) continue;
                    if (G[u].size() >= cache.size()) continue;
                    for (int k = 0; k < G[1].size(); k++){
                        int z = G[1][k];
                        if (!vis[z] || mys[z].count(u) || z == u) continue;
                        if (G[z].size() >= cache.size()) continue;
                        for (int f = 0; f < G[z].size(); f++){
                            int  v = G[z][f];
                            if (!mys[v].count(1) || !mys[v].count(u)) continue;
                            if (v == 1) continue;
                            display(1, u, v, z, u,  n);
                            return 0;
                        }
                    }
    
                }
            }
        }
        puts("-1");
        return 0;
    }
    
    /*
    5 5
    1 2
    2 3
    3 4
    4 1
    1 3
    */
    View Code
  • 相关阅读:
    模块化、结构化的代码,何尝不是在讲人生
    DOS操作文件或文件夹
    OSQL
    DOS 命令大全
    Red Tea
    SetInterval_1
    SetInterval
    分库分表——Sharding-Sphere
    线上redis热key问题
    线上redis bgsave导致服务响应延迟
  • 原文地址:https://www.cnblogs.com/heimao5027/p/8975108.html
Copyright © 2011-2022 走看看