这类问题需要利用二进制的特殊性

#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
原文地址:https://www.cnblogs.com/zhazhalovecoding/p/4870274.html