这类问题需要利用二进制的特殊性
#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("\n"); } 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\n"); continue; } solve(); print(); } return 0; }
#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\n", Map[n][m]); return; } if( mx == -1 ){ printf("0\n"); return; } if( mx == m + n ){ printf("1\n"); 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; }
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\n"); 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("\n"); } 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; }