zoukankan      html  css  js  c++  java
  • 这类问题需要利用二进制的特殊性

    #hdu 4435 charge-station#

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4435

    利用二进制的特殊性,对于第i个城市cost为2i-1,也就是说即使0~i-1号城市都建立加油站,

    花费也赶不上在i点建加油站,所以,思路:先每个城市建加油站,从高往低变了,能不建的就不建。

    对于去掉后判断时候可行,不难,一遍dfs就行:

    如果u点,v点都有加油站,dis( u, v ) <= d;

    如果u点有加油站,v点无加油站,dis( u, v ) <= d/2;(保证可以回来)

    不说了,简单题,代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<cmath>
    
    using namespace std;
    const int maxn = 200;
    int n;
    double d;
    struct Node{
        double x, y;
    }node[maxn];
    
    int vis[maxn], ans[maxn];
    
    double dis( int i, int j ){
        double x1 = node[i].x, y1 = node[i].y;
        double x2 = node[j].x, y2 = node[j].y;
    
        return ceil(sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)));
    }
    
    void dfs( int u ){
        for( int v = 1; v <= n; ++v ){
            if( v == u || vis[v] == 1 )
                continue;
            if( ans[v] == 1 && dis( u, v ) <= d ){  //v点存在加油站且可达
                vis[v] = 1;
                dfs(v);
            }else if( ans[v] == 0 && dis( u, v ) <= d/2 ){  //v点无加油站但可达
                vis[v] = 1;
            }
        }
    }
    
    bool judge( int u ){
        ans[u] = 0;
        memset( vis, 0, sizeof(vis) );
    
        vis[1] = 1;
        dfs(1);
    
        int flag = 1;
        for( int i = 1; i <= n; ++i ){
            if(vis[i] == 0){
                flag = 0;
                break;
            }
        }
    
        //回退
        ans[u] = 1;
        return flag;
    }
    
    void solve(){
        for( int i = n; i >= 2; --i ){
            if(judge(i))
                ans[i] = 0;
        }
    }
    
    void print(){
        int e = n;
        for( int i = n; i >= 1; --i ){
            if( ans[i] == 0 )
                e--;
            else
                break;
        }
    
        for( int i = e; i >= 1; --i ){
            printf("%d", ans[i]);
        }
        printf("
    ");
    }
    
    int main(){
        //freopen("4438.in", "r", stdin);
        while(scanf("%d%lf", &n, &d) != EOF){
            memset( node, 0, sizeof(node) );
            for( int i = 1; i <= n; ++i ){
                scanf("%lf%lf", &node[i].x, &node[i].y);
            }
    
            bool flag = 1;
            for( int i = 1; i <= n; ++i ){
                ans[i] = 1;
    
                bool flag1 = 0;
                for( int j = 1; j <= n; ++j ){
                    if( i == j )
                       continue;
                    if( dis( i, j ) <= d )
                        flag1 = 1;
                }
    
                if( flag1 == 0 ){
                    flag = 0;
                    break;
                }
            }
    
            //存在某一节点不可达
            if(!flag){
                printf("-1
    ");
                continue;
            }
    
            solve();
            print();
        }
    
        return 0;
    }
    View Code

    #hdu 5335 Walk Out#

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5335 

    求走过的二进制串的min,

    预处理出不得不走1的位置,对于从这些点出发,因为1打头,所以自然01串越短越好,bfs就行。

    (当时T了好几次。。。因为转移到同一个点时要比较下01串大小,结果T了。。。。

    后来改了改。。终于过了,方法:贪心,能走0尽量走0,否则才走1,这样就不存在比较大小了,每次维护的一定是最优)

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<queue>
    
    using namespace std;
    const int maxn = 1000 + 10;
    char Map[maxn][maxn];
    int n, m, mx;
    
    int vis[maxn][maxn];
    
    struct Node{
        int x, y;
        string str;
    
        Node(){
            x = 0, y = 0, str = "";
        }
        Node( int x, int y, string str ){
            this->x = x;
            this->y = y;
            this->str = str;
        }
    
        bool operator < ( const Node& node ) const{
            if( str > node.str )
                return true;
            return false;
        }
    };
    
    int dx[] = { 1, 0, -1, 0 };
    int dy[] = { 0, 1, 0, -1 };
    
    //第一遍bfs处理出起始点
    void bfs1(){
        memset( vis, 0, sizeof(vis) );
        queue< pair<int, int> > q;
        q.push(make_pair(1,1));
        vis[1][1] = 1;
    
        mx = -1;
        while(!q.empty()){
            pair<int, int> now = q.front();
            q.pop();
    
            if( Map[now.first][now.second] == '1' ){
                mx = max(mx, now.first+now.second);
                continue;
            }
    
            for( int i = 0; i < 4; ++i ){
                int tempx = now.first + dx[i];
                int tempy = now.second + dy[i];
    
                if( tempx < 1 || tempx > n || tempy < 1 || tempy > m || vis[tempx][tempy] )
                    continue;
                vis[tempx][tempy] = 1;
                q.push(make_pair(tempx, tempy));
            }
        }
    }
    
    //第二遍bfs找到可行解
    void bfs2(){
        int i, j;
        //cout << "mx:" << mx << endl;
        if( vis[n][m] == 1 ){
            printf("%c
    ", Map[n][m]);
            return;
        }
    
        if( mx == -1 ){
            printf("0
    ");
            return;
        }
    
        if( mx == m + n ){
            printf("1
    ");
            return;
        }
    
        if( mx >= n + 1 ){
            i = n, j = mx - n;
        }else{
            i = mx - 1, j = 1;
        }
    
        //cout << "i:" << i << "j:" << j << endl;
    
        //预处理出起始点
        int flag = 0;
        vector<Node> q[2];
        while( i >= 1 && j <= m ){
            if( vis[i][j] && Map[i][j] == '1' )
               q[flag].push_back(Node( i, j, "1" ));
            i--, j++;
        }
        //cout << "sz:" << q[flag].size() << endl;
    
        memset( vis, 0, sizeof(vis) );
        for( int i = 1; i <= n+m-mx; ++i ){
            q[flag^1].clear();
            int sz = q[flag].size();
            int f = 0;
            for( int j = 0; j < sz; ++j ){
                Node now = q[flag][j];
                int tempx = now.x + 1, tempy = now.y;
                if( tempx <= n && Map[tempx][tempy] == '0' ){
                    vis[tempx][tempy] = 1;
                    f = 1;
                }
                tempx = now.x, tempy = now.y + 1;
                if( tempy <= m && Map[tempx][tempy] == '0' ){
                    vis[tempx][tempy] = 1;
                    f = 1;
                }
            }
    
            if( f == 0 ){     //下一行不存在0
                int tempx = q[flag][0].x + 1, tempy = q[flag][0].y;
                //对于第一个需要特判
                if( tempx <= n ){
                    string tempStr = q[flag][0].str + Map[tempx][tempy];
                    q[flag^1].push_back(Node( tempx, tempy, tempStr ));
                }
    
                int sz = q[flag].size();
                for( int j = 0; j < sz-1; ++j ){
                    int x1 = q[flag][j].x, y1 = q[flag][j].y + 1;
                    int x2 = q[flag][j+1].x + 1, y2 = q[flag][j+1].y;
    
                    if( x1 == x2 && y1 == y2 ){
                        string tempStr = q[flag][j].str;
                        tempStr += Map[x1][y1];
                        q[flag^1].push_back(Node( x1, y1, tempStr ));
                    }else{
                        string tempStr = q[flag][j].str + Map[x1][y1];
                        q[flag^1].push_back(Node( x1, y1, tempStr ));
                        tempStr = q[flag][j+1].str + Map[x2][y2];
                        q[flag^1].push_back(Node( x2, y2, tempStr ));
                    }
                }
    
                //最后一个也需要特判一下
                tempx = q[flag][sz-1].x, tempy = q[flag][sz-1].y + 1;
                if(tempy <= m){
                    string tempStr = q[flag][sz-1].str + Map[tempx][tempy];
                    q[flag^1].push_back(Node( tempx, tempy, tempStr ));
                }
            }else{      //下一行存在0
                int tempx = q[flag][0].x + 1, tempy = q[flag][0].y;
                //对于第一个需要特判
                if( tempx <= n && vis[tempx][tempy] ){
                    string tempStr = q[flag][0].str + "0";
                    q[flag^1].push_back(Node( tempx, tempy, tempStr ));
                }
    
                int sz = q[flag].size();
                for( int j = 0; j < sz-1; ++j ){
                    int x1 = q[flag][j].x, y1 = q[flag][j].y + 1;
                    int x2 = q[flag][j+1].x + 1, y2 = q[flag][j+1].y;
    
                    if( x1 == x2 && y1 == y2 && vis[x1][y1] == 1 ){
                        string tempStr = q[flag][j].str + "0";
                        q[flag^1].push_back(Node( x1, y1, tempStr ));
                    }else{
                        if( vis[x1][y1] == 1 ){
                            string tempStr = q[flag][j].str + "0";
                            q[flag^1].push_back(Node( x1, y1, tempStr ));
                        }
                        if( vis[x2][y2] == 1 ){
                            string tempStr = q[flag][j+1].str + "0";
                            q[flag^1].push_back(Node( x2, y2, tempStr ));
                        }
                    }
                }
    
                //最后一个也需要特判一下
                tempx = q[flag][sz-1].x, tempy = q[flag][sz-1].y + 1;
                if(tempy <= m && vis[tempx][tempy]){
                    string tempStr = q[flag][sz-1].str + Map[tempx][tempy];
                    q[flag^1].push_back(Node( tempx, tempy, tempStr ));
                }
            }
    
            flag ^= 1;
        }
    
        cout << q[flag][0].str << endl;
    }
    
    int main(){
        //freopen("1009.in", "r", stdin);
        //freopen("09.out", "w", stdout);
        int T;
        scanf("%d", &T);
    
        while(T--){
            scanf("%d%d", &n, &m);
            char c;
            getchar();
            for( int i = 1; i <= n; ++i ){
                for( int j = 1; j <= m; ++j ){
                    Map[i][j] = getchar();
                }
                getchar();
            }
    
            bfs1();
            bfs2();
        }
    
        return 0;
    }
    View Code

    BNUOJ 24252 Divide

    题目链接:http://www.bnuoj.com/v3/problem_show.php?pid=24252

    二进制的特殊性,还是二分,从大的开始分,能均分尽量均分,不能均分的部分用小的凑。

    德哥教的方法好,扫两遍就行,第一遍进位,第二遍看能不能回退(注意,到某一个不能回退了就停止,原因不复杂。。。)

    再做了减法,OK~

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    using namespace std;
    const int maxn = 1e5 + 10;
    long long x[maxn], tmp[maxn], ans[maxn];
    int n, mx;
    
    void solve(){
        //向前进位
        for( int i = 0; i <= mx; ++i ){
            tmp[i] += x[i];
            tmp[i+1] += tmp[i]/2;
        }
    
        /*for( int i = mx; i >= 0; --i )
            cout << tmp[i];
        cout << endl;*/
    
        //没有分完的部分可以选择回退
        int i;
        for( i = mx; i >= 0; --i ){
            if(tmp[i]%2 == 0){    //如果怕该位位偶数,直接分
                ans[i] = 0;
            }else{                //如果该位是奇数看能否回退
                if( tmp[i] > x[i] )    //可以回退
                    tmp[i] = 0;
                else              //一旦有一个不能回退,则没有再回退的必要
                    break;
            }
        }
    
        for( i; i >= 0; --i ){
            if( tmp[i]%2 == 0 )
                ans[i] = 0;
            else
                ans[i] = 1;
        }
    
        /*for( int i = mx; i >= 0; --i )
            cout << ans[i];
        cout << endl;*/
    }
    
    void print(){
        int s = mx, e = 0;
        while( s >= 0 && ans[s] == 0 )
            s--;
        while( e <= mx && ans[e] == 0 )
            e++;
        if( s < e ){
            printf("0
    ");
            return;
        }
    
        //做减法
        int i;
        for( i = s; i > e; --i )
            ans[i] = 1 - ans[i];
        ans[e] = 1;
        //输出
        for( i = s; i >= e; --i ){
            if( ans[i] == 1 )
                break;
        }
        for( i; i >= 0; --i )
            printf("%d", ans[i]);
        printf("
    ");
    }
    
    int main(){
        //freopen("D.in", "r", stdin);
        int T, cas = 1;
        scanf("%d", &T);
    
        while(T--){
            memset( x, 0, sizeof(x) );
            memset( tmp, 0, sizeof(tmp) );
            memset( ans, 0, sizeof(ans) );
    
            scanf("%d", &n);
            mx = -1;
            int a;
            for( int i = 1; i <= n; ++i ){
                long long t;
                scanf("%d%lld", &a, &t);
                mx = max( mx, a );
                x[a] += t;
            }
    
            solve();
            printf("Case #%d: ", cas++);
            print();
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    VIM 配色方案,先保存一下
    ncurses库的介绍与安装
    win7 设置双屏壁纸
    3. Vim入门教程
    2. Vim 概念扫盲
    把Debian 设置中文环境
    静态代码块和构造代码块的区别
    jsp详解(3个指令、6个动作、9个内置对象、11个隐式对象)
    JVM虚拟机详解
    Java 的内置对象
  • 原文地址:https://www.cnblogs.com/zhazhalovecoding/p/4870274.html
Copyright © 2011-2022 走看看