专题1:输入输出 ZOJ 1045、ZOJ 1383
专题2:STL ZOJ 1649、ZOJ 1965
专题3:线段树 ZOJ 1610、ZOJ 2451
专题4:并查集 ZOJ 1789、ZOJ 2833
专题5:四分树 ZOJ 1788
专题6:最小生成树 ZOJ 1203
专题7:拓扑排序 ZOJ 1083
专题8:最短路径 ZOJ 1942、POJ 1860
专题9:二部图 ZOJ 1654
专题10:搜索算法 ZOJ 1091、ZOJ 1204、ZOJ 1217、ZOJ 1649
ZOJ 1045
#include<iostream>
using namespace std;
int main(){
double a, sum;
while(cin >> a && a){
sum = 0;
for(int i=1; ; i++){
sum += 1.0/(i+1);
if(sum >= a){
cout << i << " card(s)" << endl;
break;
}
}
}
return 0;
}
ZOJ 1383
#include<iostream>
using namespace std;
int main(){
int d;
cin >> d;
int data, count;
for(int n=0; n<d; n++) {
cin >> data;
count = 0;
while(data != 0) {
if(data%2 == 1) {
cout << count;
if(data/2 != 0) cout << " ";
}
data = data/2;
count++;
}
cout << endl;
}
return 0;
}
ZOJ 1649
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
int n, m;
struct node {
int x, y;
int time;//步行时间
}start, end;
bool operator<(const node& a, const node& b) {
return a.time > b.time;
}
char map[300][300];
int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
bool Judge(int x, int y) {
if(x < 0 || y < 0 || x >= n || y >= m) return false;
if(map[x][y] == '#') return false;
if(map[x][y] == 'r') return false;
return true;
}
int BFS() {
priority_queue<node> q;
node temp, newpos;
q.push(start);
while(!q.empty()) {
temp = q.top();
q.pop();
for(int i=0; i<4; i++) {
newpos.x = temp.x+dir[i][0];
newpos.y = temp.y+dir[i][1];
newpos.time = temp.time;
if(Judge(newpos.x, newpos.y)) {
if(map[newpos.x][newpos.y] == 'a') return temp.time+1;
if(map[newpos.x][newpos.y] == 'x') newpos.time = newpos.time+2;
else if(map[newpos.x][newpos.y] == '.') newpos.time = newpos.time+1;
q.push(newpos);
map[newpos.x][newpos.y] = '#';
}
}
}
return -1;
}
int main() {
while(scanf("%d%d", &n, &m) != EOF) {
getchar();
for(int i=0; i<n; i++) {
for(int j=0; j<m; j++) {
scanf("%c", &map[i][j]);
if(map[i][j] == 'r') {
start.x = i;
start.y = j;
}
}
getchar();
}
int ans = BFS();
if(ans != -1) printf("%d\n", ans);
else printf("Poor ANGEL has to stay in the prison all his life.\n");
}
return 0;
}
ZOJ 1965
#include<iostream>
#include<stdio.h>
#include<queue>
#include<string.h>
#include<string>
#include<sstream>
#include<algorithm>
#include<vector>
using namespace std;
//会出现n==1即输入数据(n-1)只有一个回车的情况
//所以不能用scanf或者getchar,可以用sstream类库读取数据
int f[55], ans[55];
vector<int> vec[55];
bool CMP(const int &a, const int &b) {
return a < b;
}
void DFS(int x) {
printf("(");
printf("%d",x);
int l = vec[x].size();
sort(vec[x].begin(), vec[x].end(), CMP);//vector排序
for(int i=0; i<l; i++) {
printf(" ");
DFS(vec[x][i]);
}
printf(")");
vec[x].clear();//清空vector
int main() {
int i, n = 0;
char c;
string line;
memset(ans, 0, sizeof(ans));
while(getline(cin, line)) {
stringstream ss(line);
for(n=0; ss>>f[n]; n++) {
ans[f[n]]++;
}
n--;
priority_queue<int, vector<int>, greater<int>> leafs;
for(i=1; i<=n+1; i++) {
if(!ans[i]) leafs.push(i);
}
for(i=0;i<=n;i++) {
int k = leafs.top();
leafs.pop();
vec[f[i]].push_back(k);
if(--ans[f[i]] == 0) leafs.push(f[i]);
}
if(n != -1) DFS(f[n]);
else printf("(1)");//输入为0
printf("\n");
memset(ans, 0, sizeof(ans));
}
}
ZOJ 1610
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int max = 8010;
const int nocolor = -1;//区间未被染色
const int divide = -2;//区间被拆分染色
int color[8010], ans;
struct Node {
int left, right;
int color;
}tree[33000];
//建立线段树
void BuildTree(int i, int l, int r) {
tree[i].left = l;
tree[i].right = r;
tree[i].color = nocolor;
if(tree[i].right-tree[i].left == 1) return;
int mid = (l+r)>>1;
BuildTree(i*2, l , mid);
BuildTree(i*2+1, mid, r);
}
//将区间(l,r)染色c
void UpdateColor(int i, int l, int r, int c) {
//已被染上该色
if(tree[i].color == c) return;
//将区间染色
if(l == tree[i].left && r == tree[i].right) {
tree[i].color = c;
return;
}
//若区间未被拆分,将其拆分并将子区间染色
if(tree[i].color != divide) {
tree[i*2].color = tree[i].color;
tree[i*2+1].color = tree[i].color;
tree[i].color = divide;
}
int mid = (tree[i].left+tree[i].right)/2;
//区间(l,r)在左子区间内
if(r <= mid) {
UpdateColor(i*2, l, r, c);
return;
}
//区间(l,r)在右子区间内
if(l >= mid) {
UpdateColor(i*2+1, l, r, c);
return;
}
//区间(l,r)跨越了当前区间的中点
UpdateColor(i*2, l, mid, c);
UpdateColor(i*2+1, mid, r, c);
}
//统计区间(l,r)上的颜色
void CountColor(int i) {
if(tree[i].color == nocolor) {
ans = -1;
return;
}
if(tree[i].color != divide) {
if(tree[i].color != ans) {
color[tree[i].color]++;
ans = tree[i].color;//ans标记当前颜色,防止连续线段计成多段
}
return;
}
if(tree[i].right-tree[i].left != 1) {
CountColor(i*2);
CountColor(i*2+1);
}
}
int main() {
int num, l, r, c, maxcolor;
while(~scanf("%d", &num)) {
BuildTree(1, 0, 8000);
maxcolor = 0;
while(num--) {
scanf("%d%d%d", &l, &r, &c);
UpdateColor(1, l, r, c);
if(c > maxcolor) maxcolor = c;
}
ans = -1;
memset(color, 0, sizeof(int)*(maxcolor+1));
CountColor(1);
for(int i=0; i<=maxcolor; i++) {
if(color[i]) printf("%d %d\n", i, color[i]);
}
printf("\n");
}
return 0;
}
ZOJ 2451
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int inf = 1000000;
int tree[201000];
void BuildTree(int i, int left, int right) {
tree[i] = inf;
if(left == right) return;
BuildTree(i*2, left, (left+right)/2);
BuildTree(i*2+1, (left+right)/2+1, right);
}
//实时更新线段树,使得查询时各节点的tree[i]是最小值
//i线段树的节点序号,pos已排序区间的端点值,val到达pos所需最少的sorter数
void UpdateTree(int i, int pos, int val, int left, int right) {
//若新的val更小,更新
if(tree[i] > val) tree[i] = val;
//返回点线段的状态
if(left == right) return;
//向下更新
int mid = (left+right)/2;
if(pos <= mid) UpdateTree(i*2, pos, val, left, mid);
else UpdateTree(i*2+1, pos, val, mid+1, right);
}
//查询新输入的x~y区间中可以连接新sorter的最小值并返回
//x~y是新的sorter区间,left~right是线段树的跨度
int Inquiry(int i, int x, int y, int left, int right) {
if(x <= left && y >= right) return tree[i];
//查询子区间
int ans1 = inf, ans2 = inf;
int mid = (left+right)/2;
if(x <= mid) ans1 = Inquiry(i*2, x, y, left, mid);
if(y > mid) ans2 = Inquiry(i*2+1, x, y, mid+1, right);
return ans1 < ans2 ? ans1 : ans2;
}
int main() {
int n, m;
while(~scanf("%d%d", &n, &m)) {
BuildTree(1, 1, n);
//线段树中所有区间端点值为1的tree[i]=0
UpdateTree(1, 1, 0, 1, n);
while(m--) {
int x, y;
scanf("%d%d", &x, &y);
int temp = Inquiry(1, x, y, 1, n);
UpdateTree(1, y, ++temp, 1, n);
}
printf("%d\n", Inquiry(1, n, n, 1, n));
}
return 0;
}
ZOJ 1789
#include<iostream>
#include<cstring>
using namespace std;
int parent[30002];
int n, m;
int Find(int x) {
int r = x;
while(parent[r] >= 0) {
r = parent[r];
}
while(x != r) {
int ans = parent[x];
parent[x] = r;
x = ans;
} //路径压缩
return r;
}
void Union(int x, int y) { //降维合并
int findx, findy;
findx = Find(x);
findy = Find(y);
int temp = parent[findx] + parent[findy];
if(findx != findy) {
if(parent[findx] > parent[findy]) {
parent[findy] = temp;
parent[findx] = findy;
}
else {
parent[findx] = temp;
parent[findy] = findx;
}
}
}
int main() {
cin >> n >> m;
while(n != 0 || m != 0) {
memset(parent, -1, sizeof(parent));
while(m--) {
int num, a, b;
cin >> num >> a;
while(--num) {
cin >> b;
Union(a, b);
}
}
cout << -parent[Find(0)] << endl;
cin >> n >> m;
}
return 0;
}
ZOJ 2833
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int parent[100010];
//找包含x的朋友圈的根i
int Find(int x) {
int i = x;
//找包含x的朋友圈的根i
while(parent[i] >= 0) {
i = parent[i];
}
//路径压缩,将x的朋友、x的朋友的朋友...表示为i的朋友
while(x != i) {
int temp = parent[x];
parent[x] = i;
x = temp;
}
return i;
}
//x和y成为朋友
void Merge(int x, int y) {
int fx, fy;
fx = Find(x);//找包含x的朋友圈的根fx
fy = Find(y);//找包含y的朋友圈的根fy
//朋友圈的根记录着朋友圈内人数的负数
int temp = parent[fx] + parent[fy];
//x和y原先不在同一个朋友圈,合并朋友圈
if(fx != fy) {
//x所在朋友圈合并到y所在的朋友圈
if(parent[fx] > parent[fy]) {
parent[fy] = temp;
parent[fx] = fy;
}
//y所在朋友圈合并到x所在的朋友圈
else {
parent[fx] = temp;
parent[fy] = fx;
}
}
}
int main() {
int n, m, a, b;
int num = 0;
while(scanf("%d%d", &n, &m) != EOF) {
memset(parent, -1, sizeof(int)*(n+1));
if(num) printf("\n");
printf("Case %d:\n", ++num);
while(m--) {
char c;
cin >> c;
//a和b成为朋友
if(c == 'M') {
scanf("%d%d", &a, &b);
Merge(a, b);
}
//通过查询a所在的朋友圈得到a的朋友数量
else if(c == 'Q') {
scanf("%d", &a);
printf("%d\n", -parent[Find(a)]);
}
}
}
return 0;
}
ZOJ 1788
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
class quadtree {
public:
char value[3];//00,01,1(00表示全0, 01表示全1, 1表示mixed)
quadtree *child[4];
quadtree() {
child[0] = child[1] = child[2] = child[3] = 0;
}
bool operator==(const quadtree& p) const {
//如果有孩子值为1或者存在相异值则不能合并
if(strcmp(value, "1") == 0 || strcmp(value, p.value) != 0) return 0;
else return 1;
}
};
quadtree *head;
char map[520][520], ans[10000], str[5];
int N, a[2500];
void init() {
scanf("%d", &N);
for(int i=0; i<N; i++) {
for(int j=0; j<N; j++) {
cin >> map[i][j];
}
}
str[4] = 0;
memset(ans, 0, sizeof(ans));
}
//四分树的四分,合并,剪枝,深度优先
quadtree * DFS(int r, int c, int len) {
quadtree*temp = new quadtree;
//四分到最小格
if(len == 1) {
temp->value[0] = '0';//第一个数置0
temp->value[1] = map[r][c];//第二个数则为方格中的数字
temp->value[2] = 0;//最后一位置0
return temp;
}
//将map四分
len /= 2;
temp->child[0] = DFS(r, c, len);
temp->child[1] = DFS(r, c+len, len);
temp->child[2] = DFS(r+len, c, len);
temp->child[3] = DFS(r+len, c+len, len);
//判断是否符合合并要求
bool flag = true;
for(int i=1; i<4; i++) {
if(!(*temp->child[0] == *temp->child[i])) {
flag = false;
break;
}
}
//满足要求则合并
if(flag) {
strcpy(temp->value, temp->child[0]->value);
for(int i=0; i<4; i++) {
delete temp->child[i];
temp->child[i] = 0;
}
}
else strcpy(temp->value, "1");//否则不合并,且节点值为1
return temp;
}
//将二进制转化为十进制数
void funtion(char s[]) {
int sum = 0;
for(int i=0; i<4; i++) {
sum = sum*2+str[i];
}
printf("%X", sum);
}
//层次遍历取出二进制数字字符串,并转为十六进制输出
void print() {
int i, j, m;
quadtree *temp;
queue<quadtree *> q;
q.push(head);
while(!q.empty()) {
temp = q.front();
q.pop();
//将二进制串连接起来
strcat(ans, temp->value);
//若该节点存在孩子
if(!(temp->child[0] == 0)) {
for(i=0; i<4; i++) {
q.push(temp->child[i]);
}
}
delete temp;
}
int slen =strlen(ans);//计算ans的长度
int pos=0;//标记ans当前计算的位置
//为了方便计算,将整个数字串长度补成4的倍数
//用长度求余数得i,在最前面补4-i个0
if(slen%4 != 0) {
i = slen%4;
for(j=0; j<4-i; j++) {
str[j] = 0;
}
for(m=j; m<4; m++) {
str[m] = ans[pos++]-'0';
}
funtion(str);
}
for(i=pos; i<slen; i+=4) {
for(j=0; j<4; j++) {
str[j] = ans[i+j]-'0';
}
funtion(str);
}
printf("\n");
}
int main() {
int num;
scanf("%d", &num);
while(num--) {
init();
head = DFS(0, 0, N);
print();
}
return 0;
}
ZOJ 1203
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
double dis[110][110], pos[110][2], val[110], vis[110];
double ans;
int n;
void MakeDis() {
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
dis[i][j] = sqrt((pos[i][0]-pos[j][0])*(pos[i][0]-pos[j][0])+(pos[i][1]-pos[j][1])*(pos[i][1]-pos[j][1]));
}
}
}
void Prim() {
memset(vis, 0, sizeof(vis));
//访问第一个点
vis[1] = 1;
int k;
double min, ans = 0;
//计算从第一个点出发的所有边
for(int i=1; i<=n; i++) {
val[i] = dis[1][i];
}
//要对剩下的所有点进行操作,循环总计n-1次
for(int i=2; i<=n; i++) {
k = 1; min = 10000;
//找到当前点出发的最短边,访问点k
for(int j=1; j<=n; j++) {
if(!vis[j] && val[j] < min) {
min = val[j];
k = j;
}
}
vis[k] = 1;
//记录当前距离
ans = ans+min;
//根据新访问的点到剩下未被访问的点的距离,更新最短距离
for(int j=1; j<=n; j++) {
if(!vis[j] && val[j] > dis[j][k]) {
val[j] = dis[j][k];
}
}
}
printf("The minimal distance is: %.2lf\n", ans);
}
int main() {
int t, step = 0;
while(scanf("%d", &n)) {
step++;
memset(pos, 0, sizeof(pos));
memset(dis, 0, sizeof(dis));
memset(val, 0, sizeof(val));
ans = 0;
if(n == 0) break;
if(step != 1) printf("\n");
for(int i=1; i<=n; i++) {
scanf("%lf%lf", &pos[i][0], &pos[i][1]);
}
MakeDis();
printf("Case #%d:\n", step);
Prim();
}
return 0;
}
ZOJ 1083
题目描述:每张图片由同一个字母组成的边框表示,不同图片的字母都不同。在一个区域上放置这些区域,区域最大为30*30。每张图片的四条边都一定会有字符能够显示。我们需要通过图片叠加的最终结果得到从底层到顶层的图片次序,有多种可能性时按字典序输出。
解题思路:本题的任务是推出图片的叠加次序。因此,第一步是根据整幅图的字母位置还原出每个边框的边界位置。因为每个字母只能出现在一副图片上,所以使用一个letter数组来记录字母是否已经被使用了。增加一个map数组,map[x][y]表示字母y所在边框位于字母x所在边框之上。再增加一个in数组,它记录每个字母的入度。在此基础上就可以建立拓扑排序图:遍历26个字母,假设字母1被使用了,则判断它所在的边框上是否有被其他字母覆盖,若字母2覆盖在字母1所在边框上,则字母2的入度加一,并建立由字母1指向字母2的有向边。最后根据记录入度的数组,输出最终结果。入度越低,字母所在边框的位置就越靠近底部,所以要从入度为0的点开始输出。每输出一个点就要删除该点,并删除所有从它出发的边,有向边的终点的入度减一。
程序清单如下
解题总结:特别注意,题目要求的输出顺序是从下到上,且可能有多种结果,均需要输出,可以选择递归的方式,总共递归次数要等于被使用了的字母的个数,每次都用vector记录下结果。与此同时,理解题意仍然是最困难的部分。而且很难想到根据拓扑排序求解,突破点应是有前后顺序要求的有向图。不过把叠加的层次转换成有向图也不是那么容易想到,因为始终将它看作是一个简单的平面图,然而它却是一个叠加了多层图片的立体架构。要是想到从该架构的侧面入手,就不难将它转换为有向图了。
ZOJ 1942 作业报告
题目描述:青蛙从起点到达终点的某条路径上,某石头到另一块石头的距离是跳跃的步长,而路径中最长的步长代表了青蛙走该条路径时需要的跳跃能力。我们需要找到跳跃能力的最小值,也就是说青蛙要想到达目的地,跳跃能力最小要为多少?
解题思路:本题的任务是①找到石头1到石头2的通路,②比较每条通路中距离最大的那一段,找到最短的。因此,首先需要以两点之间的欧氏距离为权值构造一个带权图。石头x到石头y间目前已知的所需跳跃能力存储在Distance数组里面,初始数值为两石头间距。源点为石头1,集合stone被划分为集合visit和集合stone-visit两个部分,初始visit中仅含有石头1。【在集合stone-visit中找到距离石头1最近的石头,访问它并将其加入visit中。然后化用求解最短路径的方法,将该点作为中转站,比较目前已知的所需跳跃能力与经过中转站得到的所需跳跃能力,根据修改规则修改石头1到达stone-visit中每个石头的所需跳跃能力。假设要从源点到石头v,中间经过石头w,从石头1到达石头v所需的跳跃能力的修改规则为 Distance(1, v) = min(Distance(1, v), max(Distance(1, w), Distance(w, v)))。】重复上述部分,知道所有的石头都被访问过了。最终Distance(1, 2)即为答案。
程序清单如下
解题总结:在这道题目中,读懂题目并且理解题意可以算是最困难的地方,在题干比较绕时,不一定要死读题目,还可以从输入输出的例子下手,通过观察它们的关系,反推回去就能够比较容易地搞清楚题目的任务。除此之外,另一个难点就是将Dijkstra算法变形以求解最终结果。这道题是单源路径问题,由此可以作为解题的一个突破口,然后简化题目,对两到三个点进行手工计算,计算过程能够发现近似于动态规划过程,并找到比较与修改的规则。由此就能顺利地完成代码。
POJ 1860
题目描述:给出若干种货币,某两种货币间可以互相兑换,兑换时需要考虑汇率并支付一定的佣金。现在有一些货币S,已知初始数额,需要我们判断是否能通过一些兑换操作,使得最后货币的种类依旧是S,且货币的数额大于初始数额?
解题思路:本题的任务是找到一个环,货币的数额经过这个环后增大。求解的第一步,我们需要根据给出的货币种类与兑换条件,将所有信息转化为图:把货币的种类作为图的顶点,将兑换过程作为顶点间动态的有向边,也就是说,边的权值不是固定的数值,而是基于函数关系,也就是汇率与佣金动态变化的。接着使用Bellman Ford算法判断是否存在正环,经过最多n-1次松弛还能继续松弛则存在正环,通过这个正环可以使得货币金额不断增多。松弛条件为货币的数额增加。循环过程中,若无法继续松弛下去,则说明不存在正环。况且这道题目的兑换都是双向的,因此只要有正环存在,那么可以通过正环使得货币无限增加,在这种情况下就算是起点没有包含在环中,按照原来的路径也可以换回起点货币。
程序清单如下
解题总结:第一次写这道题的时候,由于没有认真阅读题意,不清楚最后的货币类别需要是初始货币类别,就直接考虑了广度优先算法和深度优先算法,以此寻找一条能使货币数额增加的路径。看了别人的代码才发现理解有误,原本的做法虽然也使货币数额增大了,但是最后兑换回去可能因为汇率与佣金问题又再次减少。于是改用了Bellman Ford算法。比较难理解的是为什么只需要正环存在就能使数额增加,仔细理解了一下,只要存在正环,货币数额就能无限增长,且支持双向兑换就必定能换回初始货币,就算在兑换回去的时候有那么一些损失,但是在正环中已经无限增长,损失可以忽略不计。
ZOJ 1654
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n, m;
char map[51][51];
int x[51*51], y[51*51];//xi匹配的y顶点,yi匹配的x顶点
int xno[51][51], yno[51][51];//水平/垂直方向上块的编号
int xn, yn;//水平/垂直方向上块的个数
bool g[51*51][51*51];//水平上第i块与垂直上第j块是否有公共区域
int visit[51*51];
//从x中的点u出发用深度优先策略寻找增广路
int Path(int u) {
//考虑y中的所有点
for(int v=1; v<=yn; v++) {
//v跟u邻接并且v未访问过,访问
if(g[u][v] && !visit[v]) {
visit[v] = 1;
//v未匹配,或者v已经匹配了但从y[v]出发可以找到一条增广路
if(!y[v] || Path(y[v])) {
//更新匹配
x[u] = v;
y[v] = u;
return 1;
}
}
}
//不存在从u出发的增广路
return 0;
}
//最大匹配算法
void MaxMatch() {
int ans = 0;
memset(x, 0, sizeof(x));
memset(y, 0, sizeof(y));
//从每个未饱和点出发寻找增广路
for(int i=1; i<=xn; i++) {
if(!x[i]) {
memset(visit, 0, sizeof(visit));
if(Path(i)) ans++;
}
}
printf("%d\n", ans);
}
int main() {
int kase, num, flag;
scanf("%d", &kase);
for(int k=0; k<kase; k++) {
scanf("%d%d", &m, &n);
memset(xno, 0, sizeof(xno));
memset(yno, 0, sizeof(yno));
memset(g, 0, sizeof(g));
for(int i=0; i<m; i++) {
scanf("%s", map[i]);
}
//对水平方向上的块进行编号
num = 0;
for(int i=0; i<m; i++) {
flag = 0;
for(int j=0; j<n; j++) {
if(map[i][j] == 'o') {
if(flag == 0) num++;
xno[i][j] = num;
flag = 1;
}
else if(map[i][j] == '#') flag = 0;
}
}
xn = num;
//对垂直方向上的块进行编号
num = 0;
for(int j=0; j<n; j++) {
flag = 0;
for(int i=0; i<m; i++) {
if(map[i][j] == 'o') {
if(flag == 0) num++;
yno[i][j] = num;
flag = 1;
}
else if(map[i][j] == '#') flag = 0;
}
}
yn = num;
//连接有公共区域的水平上的块和垂直上的块
for(int i=0; i<m; i++) {
for(int j=0; j<n; j++) {
if(xno[i][j] && yno[i][j]) g[xno[i][j]][yno[i][j]] = 1;
}
}
printf("Case :%d\n", k+1);
//寻找最大匹配
MaxMatch();
}
return 0;
}
ZOJ 1091
#include <iostream>
#include <cstring>
using namespace std;
int step1[8] = {1,1,2,2,-1,-1,-2,-2};
int step2[8] = {2,-2,1,-1,2,-2,1,-1};
int knight[8][8];
void Find(int st1, int st2, int moves) {
if(st1 < 0 || st1 > 7 || st2 < 0 || st2 > 7 || moves >= knight[st1][st2]) {
return;
}
knight[st1][st2] = moves;
for(int m = 0; m < 8; m++) {
Find(st1 + step1[m], st2 + step2[m], moves + 1);
}
}
int main() {
string a, b;
while(cin >> a >> b) {
memset(knight, 100, sizeof(knight));
Find(a[0] - 'a', a[1] - '1', 0);
cout << "To get from " << a << " to " << b << " takes " << knight[b[0] - 'a'][b[1] - '1'] << " knight moves." << endl;
}
return 0;
}
ZOJ 1204
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int n, a[30], visit[30];
bool flag;//判断是否有解(即满足题意的等式)
void DFS(int start, int depth, int sum) {
if (depth == 0) { // 已经到底了
for (int i = start; i < n && sum >= a[i]; i++) {
if (sum == a[i]) {
flag = true;
for (int j = 0; j <= i; j++) {
if (visit[j]) {
if (sum == a[j]) {
//说明a[j]是等式左边最后一个加数了,下面每次sum都减去加数就是为了方便判断
cout << a[j] << "=" << a[i] << endl;
}
else cout << a[j] << "+";
sum -= a[j];
}
}
}
}
}
else { //还没到底,继续深搜
for (int i = start; i < n; i++) {
if (sum + a[i] <= a[n - 1]) {
sum += a[i];
visit[i] = 1;
--depth;
DFS(i + 1, depth, sum);
sum -= a[i];
visit[i] = 0;
++depth;
}
}
}
}
int main(void) {
int N;
cin >> N;
while(N--) {
cin >> n;
for(int i = 0; i < n; i++) {
cin >> a[i];
}
sort(a, a+n);
memset(visit, 0, sizeof(int)*30);
flag = false;
for(int i=2; i<n; i++) {//深搜深度范围为[2,n-1](深度即equation左边的数字个数)
DFS(0, i, 0);
}
if(!flag) cout << "Can't find any equations." << endl << endl;
else cout << endl;
}
return 0;
}
ZOJ 1217
#include<iostream>
#include<string>
#include<map>
#include<iterator>
#include<queue>
using namespace std;
map<string,string> m; //记录状态转换图,前后转换关系形成m映射
map<string,string>::iterator it;
queue<string> q;//广搜队列
string goal = "12345678x";
void Map(string s1,string s2,int t1,int t2){
s2 = s1;
s1[t2] = 'x';
s1[t1] = s2[t2];//建立新的状态字符串s1
it = m.find(s1);
//如果m中没有s1状态,则将其加入m
if(it == m.end()) {
m[s1] = s2;//s1是由s2转换来的
q.push(s1);//将当前搜索到的状态放入队列
}
}
void Search(){
//初始化
string s1 = goal, s2;
q.push(s1);
m[s1] = s1;//方便最后的判断,直接判映射值和goal是否相同即可
int t1, t2;
while(!q.empty()) {
//取出待搜索状态
s1 = q.front();
q.pop();
//查找x的位置,用t1记录
for(t1=0; t1<9; t1++) {
if(s1[t1] == 'x') break;
}
//不是最上面的一列,可以上移
if(t1/3 != 0) {
t2 = t1-3;
Map(s1, s2, t1, t2);
}
//不是最下面的一列,可以下移
if(t1/3 != 2) {
t2 = t1+3;
Map(s1, s2, t1, t2);
}
//不是最左边的一列,可以左移
if(t1%3 != 0) {
t2 = t1-1;
Map(s1, s2, t1, t2);
}
//不是最右边的一列,可以右移
if(t1%3 != 2) {
t2 = t1+1;
Map(s1, s2, t1, t2);
}
}
}
int main(){
int ans1, ans2;
string s, ms;
char c;
m.clear();
Search();//记录状态转换图
while(cin >> c) {
//输入初始状态s
s = "";
s += c;
for(int i=1; i<9; i++) {
cin >> c;
s += c;
}
//在m中找s
it = m.find(s);
//在m中没有找到s,unsolvable
if(it == m.end()) cout << "unsolvable" << endl;
//在m中找到s
else {
while(s != goal) {
it = m.find(s);
ms = it->second;//first得到key,second得到value
//比较s和ms,通过x的位置变化判断u/d/r/l
for(ans1=0; ans1<9; ans1++) {
if(s[ans1] == 'x') break;
}
for(ans2=0; ans2<9; ans2++) {
if(ms[ans2] == 'x') break;
}
int ans = ans2-ans1;
if(ans == -3) cout << "u";
else if(ans == 3) cout << "d";
else if(ans == 1) cout << "r";
else if(ans == -1) cout << "l";
//s变化为ms,继续搜索
s = ms;
}
cout << endl;
}
}
return 0;
}
伸展树 课件题目
#include<iostream>
#include<stdio.h>
using namespace std;
const int maxn = 1e5 + 99;
const int INF = 0x3f3f3f3f;
//不断插入节点
//将新插入的节点调整为根节点
//比较与左孩子和右孩子的差值,较小的即为最小差值
struct SpalyTree {
int ch[maxn][2], pre[maxn], sz[maxn], key[maxn], root, tot1;
void Rotate(int x, int d) {
int y = pre[x];
ch[y][!d] = ch[x][d];
pre[ch[x][d]] = y;
if (pre[y]) ch[pre[y]][ch[pre[y]][1] == y] = x;
pre[x] = pre[y];
ch[x][d] = y;
pre[y] = x;
}
void Splay(int r, int goal) {
while (pre[r] != goal) {
if (pre[pre[r]] == goal) Rotate(r, ch[pre[r]][0] == r);
else {
int y = pre[r];
int d = ch[pre[y]][0] == y;
if (ch[y][d] == r) {
Rotate(r, !d);
Rotate(r, d);
}
else{
Rotate(y, d);
Rotate(r, d);
}
}
}
if(goal == 0) root = r;
}
void Newnode(int &r, int fa, int k) {
r = ++tot1;
sz[r] = 1;
key[r] = k;
pre[r] = fa;
ch[r][0] = ch[r][1] = 0;
}
int Insert(int k) {
int r = root;
while(1) {
if(key[r] == k) {
Splay(r, 0);
return 0;
}
else if (k < key[r]) {
if(ch[r][0]) r = ch[r][0];
else {
Newnode(ch[r][0], r, k);
Splay(ch[r][0], 0);
return 1;
}
}
else if(k > key[r]) {
if(ch[r][1]) r = ch[r][1];
else {
Newnode(ch[r][1], r, k);
Splay(ch[r][1], 0);
return 1;
}
}
}
}
int GetPre(int x) {
int r = ch[x][0];
if(r == 0) return INF;
while(ch[r][1]) {
r = ch[r][1];
}
return key[x]-key[r];
}
int GetNext(int x) {
int r = ch[x][1];
if(r == 0) return INF;
while(ch[r][0]) {
r = ch[r][0];
}
return key[r]-key[x];
}
}tree;
int main() {
int n;
while(scanf("%d", &n) == 1) {
tree.root = tree.tot1 = 0;
int ans = 0;
for(int i=1; i<=n; i++) {
int num;
if(scanf("%d", &num) == EOF) num = 0;
if(i == 1) {
ans += num;
tree.Newnode(tree.root, 0, num);
continue;
}
if(tree.Insert(num) == 0) continue;
int a = tree.GetPre(tree.root);
int b = tree.GetNext(tree.root);
ans += min(a, b);
}
printf("%d\n", ans);
}
}