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
  • 相关阅读:
    Windows XP下 Android开发环境 搭建
    Android程序的入口点
    在eclipse里 新建android项目时 提示找不到proguard.cfg
    64位WIN7系统 下 搭建Android开发环境
    在eclipse里 新建android项目时 提示找不到proguard.cfg
    This Android SDK requires Android Developer Toolkit version 20.0.0 or above
    This Android SDK requires Android Developer Toolkit version 20.0.0 or above
    Android requires compiler compliance level 5.0 or 6.0. Found '1.4' instead
    Windows XP下 Android开发环境 搭建
    Android程序的入口点
  • 原文地址:https://www.cnblogs.com/heimao5027/p/8975108.html
Copyright © 2011-2022 走看看