#include
。可以将数组或容器赋任何值。
#include
。只能为int类型数组的赋值为0或-1。
初始化赋值为非0的int数组或容器,推荐使用fill。
#ifdef ONLINE_JUDGE
#else
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
头文件: #include
find函数的表示:
所有的返回,均是迭代器(容器)或指针(数组),而非是直观感觉上的索引下标。如果在查找范围内不存在,返回a.end(),这里需要注意的是,a.end()不在查找范围内。
各个容器自己实现的find成员函数:
判断元素是否存在。
题目链接:210 - Concurrency Simulator
参考博文:uva 210 - Concurrency Simulator (并行程序模拟)
代码:
#include
#include
#include
#include
#include
#include
using namespace std;
// 当前程序执行完,配额时间有剩余: 让下一个程序继续用
// 当配额时间用完,当前程序一句代码没执行完: 继续执行到完
// 多组输入
// 每组输出之间空一行
// 所有变量初值为0
// 最后一组的输出之后不要有空行
map<char, int> vars;
vector<deque<string> > group;
deque<int> stop;
deque<int> wait;
void fun(){
int N,t1,t2,t3,t4,t5,Q;
cin>>N>>t1>>t2>>t3>>t4>>t5>>Q;
getchar(); // [注意] 接收空格
//接收多组输入程序
group = vector<deque<string> >(N);
for(int i=0;i<N;i++){
string str;
while(str != "end"){
getline(cin, str);
group[i].push_back(str);
}
wait.push_back(i);
}
int index = 0; //当前第几个程序
int count_live = N;//代表还没有结束的程序个数
int lock = 0; // 作为临界资源的记录型信号量,代表阻塞程序个数
int part_time = 0; // 当前程序单位剩余时间
while(count_live){
int end_flag = 0; // 0:程序没结束, 1:程序end结束 -1:程序阻塞
index = wait[0]; // 读取等待队列首
wait.pop_front();
part_time = Q;
while(part_time>0){ // 一个单位时间剩余的时间
string code = group[index][0]; // 读取程序队列首代码
string judge = code.substr(0,2);
if(judge == "pr"){ // print
cout<<index+1<<": "<< vars[code[6]]<<endl;
part_time -= t2;
}else if(judge == "lo"){ // lock
if(lock){ // 要阻塞,语句不执行,不记时
stop.push_back(index);
end_flag = -1;
part_time = 0; // 此次时间片废了
break; // 进入阻止队列,就不用进入等待队列了, 而且lock代码还需要执行
}else{ // 如果还没有lock的程序,正常执行
lock++;
part_time -= t3;
}
}else if(judge == "un"){ // unlock
int pro = stop[0];
if(!stop.empty()){ // 若是最后一个解锁的,那么阻塞队列就是空
stop.pop_front();
wait.push_front(pro);
}
lock--;
part_time -= t4;
}else if(judge == "en"){ // end
count_live --;
part_time -= t5;
end_flag = 1;
break; // 结束本程序,时间片给下一个
}else{ // var
int n;
sscanf(code.substr(4).c_str(), "%d",&n);
vars[judge[0]] = n;
part_time -= t1;
}
group[index].pop_front(); // 执行成功,代码出队列
}
if(end_flag == 0)
wait.push_back(index); // 时间片完,只要程序没有end, 就会入wait队列
}
}
int main()
{
int T;
cin>>T;
for(int i=0;i<T;i++){
if(i>0)
cout<<endl;
//初始化
vars.clear();
group.clear();
stop.clear();
wait.clear();
fun();
}
return 0;
}
题目链接:514 - Rails
代码:
#include
#include
#include
#include
using namespace std;
int main()
{
stack<int> q;
int a[5000], N, kase = 0;
while(cin >> N && N)
{
while(cin >> a[1] && a[1])
{
//清空栈
while(!q.empty()) q.pop();
for(int i=2; i<=N; i++)
cin >> a[i];
int cnt = 1;
for(int i=1; i<=N; i++)//按序进栈
{
q.push(i);
while(!q.empty() && a[cnt]==q.top())//比较栈顶是否可以出栈
q.pop(), cnt++;//遍历下一个出栈序号
}
if(q.empty())//栈空,则为真
printf("Yes\n");
else
printf("No\n");
}
printf("\n");
}
return 0;
}
题目链接:442 - Matrix Chain Multiplication
代码:
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
struct Node
{
int r, c;
Node(int r=-1, int c=-1):r(r), c(c){}
};
map<char, Node>m;
stack<Node> stc;
string s;
int main()
{
int n, r, c;
char ch;
cin >> n;
for(int i=0; i<n; i++)
{
cin >> ch >> r >> c;
m[ch] = Node(r, c);
}
while(cin >> s)
{
while(!stc.empty()) stc.pop();
LL sum = 0, flag = 1;
for(int i=0; i<s.size(); i++)
{
if(isalpha(s[i]))//判断为字母
{
stc.push(m[s[i]]);
}
else if(s[i]==')')//计算
{
Node a = stc.top(); stc.pop();
Node b = stc.top(); stc.pop();
if(b.c!=a.r)//无法计算
{
flag = 0;
break;
}
else//可以计算
{
stc.push(Node(b.r, a.c));
sum += b.r*b.c*a.c;
}
}
}
if(flag) printf("%lld\n", sum);
else printf("error\n");
}
return 0;
}
题目链接:11988 - Broken Keyboard (a.k.a. Beiju Text)
代码:
#include
#include
#include
#include
#include
using namespace std;
list<char> s;
char ch;
int main()
{
int flag = 1, cnt = 0;
list<char>::iterator it;
while(ch=getchar())
{
if(ch==EOF) break;
if(ch=='\n')
{
for(it=s.begin(); it!=s.end(); it++)
printf("%c", *it);
printf("\n");
s.clear();
}
else if(ch==']') cnt = s.size();
else if(ch=='[') cnt = 0;
else
{
if(cnt==0)//当前面一个字符是'['
{
it = s.begin();//迭代器移到最前面
s.push_front(ch);
}
else if(cnt==s.size())//当遇到[后或初始状态
{
s.push_back(ch);//在字符串后面添加
}
else
{
s.insert(it, ch);//在it指向的元素(原首部元素)的前方插入元素
}
cnt++;
}
}
return 0;
}
题目链接:12657 - Boxes in a Line12657 - Boxes in a Line
代码:
#include
#include
using namespace std;
const int MAX = 100005;
int Right[MAX], Left[MAX];
//连接函数,方便操作
void link(int L, int R)
{
Right[L] = R;
Left[R] = L;
}
int main()
{
int m, n, kase = 0;
while(scanf("%d%d", &n, &m)!=EOF)
{
for(int i=1; i<=n; i++)
{
Left[i] = i-1;
Right[i] = (i+1)%(n+1);
}
Right[0] = 1, Left[0] = n;
int op, X, Y, inv = 0;
while(m--)
{
scanf("%d", &op);
if(op==4) inv = !inv;
else
{
scanf("%d%d", &X, &Y);
if(op==3 && Right[Y]==X) swap(X, Y);//方便后面推断翻转是否相邻,将相邻情况处理成一种
if(op!=3 && inv) op = 3-op;//对于操作1和2,对于翻转有对称性
if(op==1 && X==Left[Y]) continue;
if(op==2 && X==Right[Y]) continue;
int LX = Left[X], RX = Right[X], LY = Left[Y], RY = Right[Y];
if(op==1)
{
link(LX, RX); link(LY, X); link(X, Y);
}
else if(op==2)
{
link(LX, RX); link(Y, X); link(X, RY);
}
else if(op==3)
{
if(Right[X]==Y)//相邻的情况需要单独处理
{
link(LX, Y); link(Y, X); link(X, RY);
}
else
{
link(LX, Y); link(Y, RX); link(LY, X); link(X, RY);
}
}
}
}
int b = 0;
long long ans = 0;
for(int i=1; i<=n; i++)
{
b = Right[b];
if(i%2) ans += b;
}
//对于翻转次数为奇数,长度为偶数
if(inv && n%2==0) ans = (long long)n*(n+1)/2-ans;
printf("Case %d: %lld\n", ++kase, ans);
}
return 0;
}
题目链接:679 - Dropping Balls
直接模拟(超时)代码:
#include
#include
#include
#include
using namespace std;
const int MAX = 1<<21;
int flag[MAX];
void Init(int D)
{
int m = 1<<D;
memset(flag, 0, sizeof(flag));
}
int main()
{
int T, D, I;
while(scanf("%d", &T)==1 && T!=-1)
{
while(T--)
{
scanf("%d%d", &D, &I);
Init(D);
int cnt = 1, i = 1, ans;
while(i<=I)
{
if(flag[cnt]==0)
{
flag[cnt] = 1;
cnt = cnt*2;
}
else
{
flag[cnt] = 0;
cnt = cnt*2+1;
}
if(cnt>=1<<(D-1))
{
ans = cnt;
cnt = 1;
i++;
}
}
printf("%d\n", ans);
}
}
return 0;
}
AC代码:
#include
#include
#include
#include
using namespace std;
int main()
{
int T, D, I;
while(scanf("%d", &T)==1 && T!=-1)
{
while(T--)
{
scanf("%d%d", &D, &I);
int k = 1;
for(int i=0; i<D-1; i++)
{
if(I%2)//奇数
{
k = k*2;//左子
I = (I+1)/2;//向左走的第I个小球
}
else
{
k = k*2+1;//右子
I /= 2;//向右走的第I个小球
}
}
printf("%d\n", k);
}
}
return 0;
}
题目链接:122 - Trees on the level
题目大意:输入一棵二叉树,你的任务是按从上到下、从左到右的顺序输出各个结点的值。每个结点都按照从根结点到它的移动序列给出(L表示左,R表示右)。在输入中,每个结点的左括号和右括号之间没有空格,相邻结点之间用一个空格隔开。每棵树的输入用一对空括号“()”结束(这对括号本身不代表一个结点),如图6-3所示。
注意,如果从根到某个叶结点的路径上有的结点没有在输入中给出,或者给出超过一次,应当输出-1。结点个数不超过256。
样例输入:
(11,LL) (7,LLL) (8,R) (5,) (4,L) (13,RL) (2,LLR) (1,RRR) (4,RR) ()
(3,L) (4,R) ()
样例输出:
5 4 8 11 13 4 7 2 1
not complete
思路:我使用了模拟法。对于"LR"的路径,"L"代表序号乘以2,"R"代表序号乘以2+1。然后使用map将序号与编号映射起来,在使用set存储所有序号。如果序号重复或父节点不存在,则表明该树不存在,否则按序号顺序输出编号即可。
代码:
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAX = 100000;
map<int, string> m;//树的序号与编号的映射
set<int> Set;//存储所有遍历到的树的序号
string s;
int flag;//标记是否是二叉树
//初始化函数
void Init()
{
flag = 1;
Set.clear();
m.clear();
}
int main()
{
Init();
while(cin >> s)
{
if(s=="()")
{
set<int>::iterator it;
if(flag)
{
//遍历判断是否是一个树
for(it=Set.begin(); it!=Set.end(); it++)
{
if(*it==1) continue;
if(m.count((*it)/2)==0)//判断其父节点是否存在
{
flag = 0;
break;
}
}
}
if(!flag)
{
printf("not complete\n");
}
else
{
//打印输出结果
for(it=Set.begin(); it!=Set.end(); it++)
{
if(it!=Set.begin()) printf(" ");
printf("%s", m[*it].c_str());
}
printf("\n");
}
Init();
continue;
}
int len = s.size();
int k = s.find(',');
//分割字符串
string id = s.substr(1, k-1);
string path = s.substr(k+1, len-k-1);
int cnt = 1;
for(int i=0; i<path.size(); i++)
{
if(path[i]=='L') cnt = cnt*2;
else if(path[i]=='R') cnt = cnt*2+1;
}
if(m.count(cnt)==0) m[cnt] = id;//存储结点
else flag = 0;//路径重复
Set.insert(cnt);
}
return 0;
}
书中的代码:
#include
#include
#include
#include
using namespace std;
const int maxNum = 256 + 5;
// 二叉树节点类型
struct Node {
// 是否被赋值
bool isAssign;
// 值
int value;
// 左子节点
Node *left;
// 右子节点
Node *right;
// 构造方法
Node() : isAssign(false), left(NULL), right(NULL){ }
};
// 根节点
Node *root;
// 是否有错
bool failed;
// 创建一个新节点
Node * newNode() {
return new Node();
}
// 递归释放二叉树
void removeTree(Node *p) {
// 节点为空返回
if(p == NULL) {
return;
}
// 删除左子树
removeTree(p->left);
// 删除右子树
removeTree(p->right);
// 调用对象p的析构方法释放p节点占用的内存
delete p;
}
// val为插入节点的值
// seq为插入节点的序列
void insertNode(int val, char* seq) {
int n = strlen(seq);
Node *p = root;
// 循环读取插入结点序列
// 包含了根节点的情况
for(int i = 0; i < n; i++) {
// 往左子树走
if(seq[i] == 'L') {
// 左子节点不存在
if(p->left == NULL) {
// 创建一个新节点,并挂在p的左子节点域上
p->left = newNode();
}
// 指向该节点
p = p->left;
} else if(seq[i] == 'R') {
if(p->right == NULL) {
// 创建一个新节点,并挂在p的右子节点域上
p->right = newNode();
}
// 指向该节点
p = p->right;
}
}
// 已经赋值过了,则表示输入有误
if(p->isAssign) {
failed = true;
}
p->value = val;
// 标记已赋值
p->isAssign = true;
}
char s[maxNum];
// 读取输入
bool readInput() {
// 移除上一颗二叉树
removeTree(root);
// 初始化
failed = false;
root = newNode();
while(true) {
if(scanf("%s", s) != 1) {
return false;
}
// ()退出输入节点
if(!strcmp(s, "()")) {
break;
}
// 字符串转数字
int val;
sscanf(&s[1], "%d", &val);
// 插入节点
insertNode(val, strchr(s, ',') + 1);
}
return true;
}
// 广度优先遍历
// 返回值为是否某一节点未被赋值
bool bfs(vector<int> &ans) {
// 广度优先遍历所需要的队列
queue<Node *> q;
// 清除上一次的序列
ans.clear();
// 初始时只有一个根节点
q.push(root);
while(!q.empty()) {
Node *p = q.front();
q.pop();
// 表示有节点未被赋值
if(!p->isAssign) {
return false;
}
// 将序列加入结果容器
ans.push_back(p->value);
if(p->left != NULL) {
// 左子节点入栈
q.push(p->left);
}
if(p->right != NULL) {
// 右子节点入栈
q.push(p->right);
}
}
return true;
}
int main() {
// 层次遍历序列
vector<int> ans;
while(readInput()) {
// 通过广度优先遍历,也就是队列得到层次遍历序列
if(!bfs(ans)) {
failed = true;
}
if(failed) {
printf("not complete\n");
} else {
for(int i = 0; i < ans.size(); i++) {
if(i != 0) {
printf(" ");
}
printf("%d", ans[i]);
}
printf("\n");
}
}
return 0;
}
题目链接:548 - Tree
代码:
#include
#include
#include
#include
using namespace std;
const int maxv = 10010;
int in_order[maxv], post_order[maxv], lch[maxv], rch[maxv];
int n, best, best_sum;
//处理读取的字符串
bool read_list(int *a)
{
string line;
if(!getline(cin, line)) return false;
stringstream ss(line);
n = 0;
int x;
while(ss >> x) a[n++] = x;
return n>0;
}
//把in_order[L1..R1]和post_order[L2...R2]建成一棵二叉树
int build(int L1, int R1, int L2, int R2)
{
if(L1>R1) return 0;
int root = post_order[R2];//当前子树的根节点
int p = L1;
while(in_order[p]!=root) p++;//在中序中寻找根节点
int cnt = p-L1;//子树的长度
lch[root] = build(L1, p-1, L2, L2+cnt-1);
rch[root] = build(p+1, R1, L2+cnt, R2-1);
return root;
}
void dfs(int u, int sum)
{
sum += u;
if(!lch[u] && !rch[u])
{
if(sum<best_sum || (sum==best_sum && u<best))
best_sum = sum, best = u;
}
if(lch[u]) dfs(lch[u], sum);
if(rch[u]) dfs(rch[u], sum);
}
int main()
{
while(read_list(in_order))
{
read_list(post_order);
build(0, n-1, 0, n-1);
best_sum = 1000000000;//赋初值
dfs(post_order[n-1], 0);
cout << best << endl;
}
return 0;
}
题目链接:839 - Not so Mobile
代码:
#include
#include
using namespace std;
bool solve(int &W)
{
int W1, W2, D1, D2;
bool b1 = true, b2 = true;
cin >> W1 >> D1 >> W2 >> D2;
if(!W1) b1 = solve(W1);//检查左子树是否平衡,并计算左子树的总重量
if(!W2) b2 = solve(W2);//检查右子树是否平衡,并计算右子树的总重量
W = W1+W2;//计算当前树的总重量,向上一层传值
return b1 && b2 &&(W1*D1==W2*D2);//左右子树和当前树是否平衡
}
int main()
{
int T, W;
cin >> T;
while(T--)
{
if(solve(W)) cout << "YES" << endl;
else cout << "NO" << endl;
if(T) cout << endl;
}
return 0;
}
题目链接:699 - The Falling Leaves
5 7 -1 6 -1 -1 3 -1 -1
8 2 9 -1 -1 6 5 -1 -1 12 -1 -1 3 7 -1 -1 -1
-1
样例输出:
Case 1:
7 11 3
Case 2:
9 7 21 15
代码:
#include
#include
#include
using namespace std;
const int MAX = 10010;
int ans[MAX], x;
void build(int cnt)
{
cin >> x;
if(x!=-1)
{
ans[cnt] += x;
build(cnt-1);
build(cnt+1);
}
}
int main()
{
int root, kase = 1;
while(cin >> root && root!=-1)
{
memset(ans, 0, sizeof(ans));
int pos = MAX/2;//根节点在位置中间
ans[pos] = root;
build(pos-1);
build(pos+1);
int p = pos;
while(ans[p]!=0) p--;//寻找最左边的叶节点
p = p+1;
printf("Case %d:\n", kase++);
while(ans[p+1])//输出
{
printf("%d ", ans[p++]);
}
printf("%d\n\n", ans[p]);
}
return 0;
}
题目链接:297 - Quadtrees
样例输入:
3
ppeeefpffeefe
pefepeefe
peeef
peefe
peeef
peepefefe
样例输出:
There are 640 black pixels.
There are 512 black pixels.
代码:
#include
#include
#include
#include
using namespace std;
const int MAX = 500;
int buf[33][33], ans;
char ch;
//以(r,c)为左上角,w长度的区域内判断其颜色
void solve(int r, int c, int w)
{
ch = getchar();//获得输入
if(ch=='p')//四个编号
{
solve(r, c+w/2, w/2);
solve(r, c, w/2);
solve(r+w/2, c, w/2);
solve(r+w/2, c+w/2, w/2);
}
else if(ch=='f')
{
//黑色赋值
for(int i=r; i<r+w; i++)
{
for(int j=c; j<c+w; j++)
{
if(buf[i][j]==0)
buf[i][j] = 1, ans++;
}
}
}
}
int main()
{
int T;
cin >> T;
getchar();
while(T--)
{
ans = 0;
memset(buf, 0, sizeof(buf));
//两个树累加
solve(0, 0, 32);
getchar();
solve(0, 0, 32);
getchar();
printf("There are %d black pixels.\n", ans);
}
return 0;
}
题目链接:572 - Oil Deposits
代码:
#include
#include
#include
using namespace std;
const int MAX = 101;
string f[MAX];
int m, n;
int dx[8] = {0, 1, 0, -1, 1, 1, -1, -1};
int dy[8] = {1, 0, -1, 0, 1, -1, 1, -1};
void dfs(int r, int c)
{
f[r][c] = '*';
for(int i=0; i<8; i++)
{
int x = r+dx[i], y = c+dy[i];
if(x<0 || x>=m || y<0 || y>=n) continue;
if(f[x][y]=='@') dfs(x, y);
}
}
int main()
{
while(cin >> m >> n && (n+m))
{
getchar();
for(int i=0; i<m; i++)
getline(cin, f[i]);
int ans = 0;
for(int i=0; i<m; i++)
{
for(int j=0; j<n; j++)
{
if(f[i][j]=='@')
dfs(i, j), ans++;
}
}
printf("%d\n", ans);
}
return 0;
}
题目链接:1103 - Ancient Messages
代码:
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAX = 300;
string t[MAX], s[MAX];//t是输入的十六进制,s是转换的二进制
int vis[MAX][MAX];//矩阵的编号,-1代表未遍历
vector<int> v;//记录二进制各个'1'的编号
set<int> Set[MAX];//记录圈圈,方便根据圈圈个数查找相应字符串
map<int, char> mp;//圈圈个数与相应字符的映射
vector<char> ans;//存储答案字符
int dx[5] = {0, 0, 1, -1};
int dy[5] = {1, -1, 0, 0};
int m, n, len;
//初始化各种容器
void Init()
{
v.clear();
ans.clear();
for(int i=0; i<m+2; i++)
s[i].clear();
memset(vis, -1, sizeof(vis));
}
//将一个十六进制的数字转换为二进制字符串
void Transform(int n, int i)//n是十六进制数字,i是下标
{
int a = n, b = n, len = 0;
string cur = "";
while(a)
{
b = a%2;
cur = char(b+'0')+cur;
a = a/2;
len++;
}
while(len++<4)
cur = '0'+cur;
s[i] += cur;
}
//dfs为各个元素打上编号,相邻相等的元素的编号相同
void dfs(int r, int c, int cnt)
{
vis[r][c] = cnt;
for(int i=0; i<4; i++)
{
int x = r+dx[i], y = c+dy[i];
if(x>=0 && x<m && y>=0 && y<=n && s[r][c]==s[x][y] && vis[x][y]==-1)
{
dfs(x, y, cnt);
}
}
}
int main()
{
int kase = 1;
mp[0] = 'W', mp[1] = 'A', mp[2] = 'K';
mp[3] = 'J', mp[4] = 'S', mp[5] = 'D';
while(cin >> m >> n && (m+n))
{
getchar();
Init();
for(int i=1; i<=m; i++)
{
getline(cin, t[i]);
for(int j=0; j<n; j++)
{
if(isdigit(t[i][j]))
Transform(t[i][j]-'0', i);
else
Transform(t[i][j]-'a'+10, i);
}
}
//为s的上下左右各添加一行存储'0',方便遍历和判断
len = s[1].size();
for(int j=0; j<len; j++)
{
s[0]+='0';
s[m+1]+='0';
}
m += 2;
for(int i=0; i<m; i++)
{
s[i] += '0';
s[i] = '0'+s[i];
}
n = len+2;
//遍历,打上编号
int cnt = 0;
for(int i=0; i<m; i++)
{
for(int j=0; j<n; j++)
{
if(vis[i][j]==-1)//还未遍历过
{
dfs(i, j, cnt++);
if(s[i][j]=='1')//'1'的不同编号
v.push_back(cnt-1);
}
}
}
//再次遍历,寻找圈圈
for(int i=0; i<m; i++)
{
for(int j=0; j<n; j++)
{
if(s[i][j]=='1')
{
for(int k=1; k<5; k++)
{
int x = i+dx[k], y = j+dy[k];
//'1'周围编号不为0的'0'一定是被围起来的
if(x>=0 && x<m && y>=0 && y<n && s[x][y]=='0' && vis[x][y]!=0)
{
Set[vis[i][j]].insert(vis[x][y]);//可以得到被相同编号的'1'围起来了多少种'0',即圈圈的个数
}
}
}
}
}
//根据不同的'1'围起来的圈圈的个数查找出现的字符
for(int i=0; i<v.size(); i++)
{
int cnt = Set[v[i]].size();
ans.push_back(mp[cnt]);
Set[v[i]].clear();
}
//排序
sort(ans.begin(), ans.end());
//输出
printf("Case %d: ", kase++);
for(int i=0; i<ans.size(); i++)
{
printf("%c", ans[i]);
}
printf("\n");
}
return 0;
}
题目链接:816 - Abbott’s Revenge
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
string name, signs;
int sx, sy, ex, ey, x, y;
char dirs;
string d = "NWSE";
map<char, int> m;//'NWSE’与数字的映射
map<int, vector<char> > s[10][10];//记录各个路口的标志方向
int vis[10][10][5];//标记是否已经遍历过,坐标和方向
struct Node
{
int r, c, dir;
Node(int r=-1, int c = -1, int dir=-1):r(r), c(c), dir(dir){}
bool operator < (const Node &A) const
{
if(r==A.r)
{
if(c==A.c)
{
return dir<A.dir;
}
else return c<A.c;
}
else return r<A.r;
}
};
queue<Node> q;//队列用于bfs遍历
stack<Node> stc;//用来使得路径正序
map<Node, Node> pre;//储存路径,用来寻路
//初始化
void Init()
{
memset(vis, 0, sizeof(vis));
pre.clear();
for(int i=0; i<10; i++)
{
for(int j=0; j<10; j++)
s[i][j].clear();
}
}
void bfs(Node u)
{
Node n;
while(!q.empty()) q.pop();
q.push(u);
while(!q.empty())
{
Node v = q.front(); q.pop();
vis[v.r][v.c][v.dir] = 1;
if(v.r==ex && v.c==ey)//到达目的地
{
n = v;
break;
}
if(s[v.r][v.c].count(v.dir)==0) continue;
int len = s[v.r][v.c][v.dir].size();//通过坐标的朝向得到下一步的方向
//遍历下一步
for(int j=0; j<len; j++)
{
int dir_next = v.dir, r_next, c_next;
if(s[v.r][v.c][v.dir][j]=='L')
{
dir_next = (v.dir+1+4)%4;
if(v.dir==0) r_next = v.r, c_next = v.c-1;
else if(v.dir==1) r_next = v.r+1, c_next = v.c;
else if(v.dir==2) r_next = v.r, c_next = v.c+1;
else if(v.dir==3) r_next = v.r-1, c_next = v.c;
}
else if(s[v.r][v.c][v.dir][j]=='R')
{
dir_next = (v.dir-1+4)%4;
if(v.dir==0) r_next = v.r, c_next = v.c+1;
else if(v.dir==1) r_next = v.r-1, c_next = v.c;
else if(v.dir==2) r_next = v.r, c_next = v.c-1;
else if(v.dir==3) r_next = v.r+1, c_next = v.c;
}
else
{
if(v.dir==0) r_next = v.r-1, c_next = v.c;
else if(v.dir==1) r_next = v.r, c_next = v.c-1;
else if(v.dir==2) r_next = v.r+1, c_next = v.c;
else if(v.dir==3) r_next = v.r, c_next = v.c+1;
}
if(r_next>=1 && r_next<=9 && c_next>=1 && c_next<=9 && vis[r_next][c_next][dir_next]==0)//判断是否可以作为下一步点
{
q.push(Node(r_next, c_next, dir_next));
pre[Node(r_next, c_next, dir_next)] = v;//用来储存路径
}
}
}
if(n.r==-1)//表明没有到达目的地
{
printf(" No Solution Possible\n");
return;
}
//用栈使得逆序路径正过来
while(1)
{
stc.push(n);
if(n.r==u.r && n.c==u.c && n.dir==u.dir) break;
n = pre[n];
}
//按格式输出
printf(" (%d,%d)", sx, sy);
int cnt = 2;
while(!stc.empty())
{
if((cnt-1)%10==0) printf(" ");
printf(" (%d,%d)", stc.top().r, stc.top().c);
if(cnt%10==0 && cnt>0) printf("\n");
cnt++;
stc.pop();
}
if((cnt-1)%10)
printf("\n");
}
int main()
{
m['N'] = 0, m['W'] = 1;
m['S'] = 2, m['E'] = 3;
while(cin >> name && name!="END")
{
Init();
//处理输入
cin >> sx >> sy >> dirs >> ex >> ey;
while(cin >> x && x)
{
cin >> y;
while(cin >> signs && signs!="*")
{
for(int i=1; i<signs.size(); i++)
s[x][y][m[signs[0]]].push_back(signs[i]);
}
}
printf("%s\n", name.c_str());
//从初始点得到下一个点
Node u = Node(sx, sy, m[dirs]);
if(u.dir==0) u.r = u.r-1;
else if(u.dir==1) u.c = u.c-1;
else if(u.dir==2) u.r = u.r+1;
else if(u.dir==3) u.c = u.c+1;
if(u.r<1 || u.r>9 || u.c<1 || u.c>9)
{
printf(" No Solution Possible\n");
continue;
}
bfs(u);
}
return 0;
}
题目链接:10305 - Ordering Tasks
拓扑排序的两种方法:UVA - 10305 Ordering Tasks(拓扑排序模板题)
代码:
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAX = 105;
int n, m, x, y;
int G[MAX][MAX], in_degree[MAX];
vector<int> ans;
bool toposort()
{
queue<int> q;
for(int i=1; i<=n; i++)//取所有入度为0的点
{
if(in_degree[i]==0)
q.push(i);
}
while(!q.empty())//如果存在环的图,那么一定存在无论如何去除边均存在入度不为0的点
{
int u = q.front(); q.pop();
ans.push_back(u);//存结果
for(int i=1; i<=n; i++)
{
if(G[u][i])//存在出度的边
{
G[u][i] = 0;//删除该边
in_degree[i]--;//入度减一
if(in_degree[i]==0)
q.push(i);
}
}
}
if(ans.size()<n) return 0;
else return 1;
}
int main()
{
while(scanf("%d%d", &n, &m)==2 && (n+m))
{
//初始化
ans.clear();
memset(G, 0, sizeof(G));
memset(in_degree, 0, sizeof(in_degree));
while(m--)
{
scanf("%d%d", &x, &y);
G[x][y] = 1;
in_degree[y]++;
}
if(toposort())
{
for(int i=0; i<ans.size(); i++)
{
if(i) printf(" ");
printf("%d", ans[i]);
}
printf("\n");
}
else
printf("No\n");
}
return 0;
}
使用dfs的拓扑排序:
#include
#include
const int maxn=100;
int n,m,u,v,t,topo[maxn],G[maxn][maxn],c[maxn];
//DFS
bool dfs(int u){
c[u]=-1;//正在访问中
for(int i=0;i<n;i++)if(G[u][i]){
if(c[i]<0)return false;//存在环,退出
if(!c[i]&&!dfs(i))return false;//i没访问过且访问后发现有环,退出
}
c[u]=1;topo[--t]=u;//u顶点访问完毕,修改状态,加入拓扑序列首部
return true;
}
//topological ordering
bool toposort(){
t=n;
memset(c,0,sizeof(c));
for(int i=0;i<n;i++)
if(!dfs(i))return false;
return true;
}
题目链接:10129 - Play on Words
代码:
#include
#include
#include
#include
using namespace std;
int G[50][50];
int indeg[50], outdeg[50];
int cnt, vis[50];
void dfs(int u)
{
vis[u] = 1;
cnt++;//记录连通图中点的个数
for(int i=0; i<26; i++)
{
if(!vis[i] && G[u][i])
{
dfs(i);
}
}
}
int main()
{
int n, T;
string s;
cin >> T;
while(T--)
{
cin >> n;
memset(G, 0, sizeof(G));
memset(indeg, 0, sizeof(indeg));
memset(outdeg, 0, sizeof(outdeg));
memset(vis, 0, sizeof(vis));
set<int> S;
for(int i=1; i<=n; i++)
{
cin >> s;
int len = s.size();
G[s[0]-'a'][s[len-1]-'a'] = 1;//是一个有向图
indeg[s[len-1]-'a']++;
outdeg[s[0]-'a']++;
S.insert(s[len-1]-'a'), S.insert(s[0]-'a');
}
int dif = 0, in = 0, out = 0, st = *S.begin();//st一定取到没有入度的点,出发是个欧拉回路
set<int>::iterator it;
for(it=S.begin(); it!=S.end(); it++)
{
dif = indeg[*it]-outdeg[*it];
if(dif>0) in += dif;
else if(dif<0) out += -dif;
if(!indeg[*it]) st = *it;
}
if(in>1 || out>1 || in!=out)//欧拉道路的判断条件
{
cout << "The door cannot be opened." << endl;
continue;
}
cnt = 0;//连通图中的结点数
dfs(st);
if(cnt<S.size()) cout << "The door cannot be opened." << endl;
else cout << "Ordering is possible." << endl;
}
return 0;
}
题目链接:10562 - Undraw the Trees
我的代码:
#include
#include
#include
#include
#include
using namespace std;
set<char> Set;
char ch;
string ans, s[300];
int n;
//ch:该子树的根字符,m是当前字符结点行,st是该行起始点,ed是该行终止点,二者用于划分子树范围
void solve(char ch, int m, int st, int ed)
{
ans = ans+ch+'(';//添加字符
int len = s[m].size()-1;
ed = min(ed, len);//防止子树范围大于该行字符的大小
for(int i=st; i<=ed; i++)
{
int x1 = 0, x2 = s[m+2].size()-1;//用于标记下一个子树范围
if(Set.count(s[m][i])==0)//判断是字符结点
{
if(m<n && s[m+1][i]=='|')//表明该结点可以作为下一个子树的根节点
{
//寻找下一个子树的范围x1-x2
for(int j=i; j>=0; j--)
{
if(s[m+2][j]!='-')
{
x1 = j+1;
break;
}
}
for(int j=i; j<s[m+2].size(); j++)
{
if(s[m+2][j]!='-')
{
x2 = j-1;
break;
}
}
solve(s[m][i], m+3, x1, x2);
}
else//该结点下没有子树
{
ans = ans+s[m][i]+'('+')';
}
}
}
ans += ')';
}
int main()
{
int T, mid;
cin >> T;
//操作字符
Set.insert('-'), Set.insert('|');
Set.insert(' '), Set.insert('#');
getchar();
while(T--)
{
n = 0;//代表最大行下标
ans = "(";
while(getline(cin, s[n++]))
{
if(s[n-1]=="#") break;
}
n -= 2;
if(n<0)//表明没有字符结点
{
printf("()\n");
continue;
}
//寻找根节点及其位置
for(int i=0; i<s[0].size(); i++)
{
if(Set.count(s[0][i])==0)
{
ch = s[0][i];
mid = i;
break;
}
}
if(n==0)
{
printf("(%c())\n", ch);
continue;
}
//寻找第一个子树的范围
int x1 = 0, x2 = s[2].size()-1;
for(int i=mid; i>=0; i--)
{
if(s[2][i]!='-')
{
x1 = i+1;
break;
}
}
for(int i=mid; i<s[2].size(); i++)
{
if(s[2][i]!='-')
{
x2 = i-1;
break;
}
}
solve(ch, 3, x1, x2);
ans += ')';
printf("%s\n", ans.c_str());
}
return 0;
}
书上的代码:
#include
#include
#include
#include
using namespace std;
const int maxn=210;
int n;
char a[maxn][maxn];
//r表示行下标,c表示列下标
void dfs(int r,int c)
{
printf("%c(",a[r][c]);
if(r+1<n&&a[r+1][c]=='|')//可以递归子树
{
int i=c;
while(i-1>=0&&a[r+2][i-1]=='-')//找到下一个指数的列的起始点
i--;
while(a[r+2][i]=='-'&&a[r+3][i]!='\0')//r+2行的'-'范围和r+3行的字符串长度范围均需要满足
{
if(!isspace(a[r+3][i]))
dfs(r+3,i);
i++;
}
}
printf(")");
}
void solve()
{
n=0;//表示有效字符行数
while(1)
{
gets(a[n]);
if(a[n][0]=='#')
break;
else
n++;
}
printf("(");
if(n)
{
for(int i=0;i<=strlen(a[0]);i++)//寻找根节点字符
{
if(a[0][i]!=' ')
{
dfs(0,i);
break;
}
}
}
printf(")\n");
}
int main()
{
int T;
scanf("%d",&T);
getchar();
while(T--)
{
solve();
}
}
题目链接:12171 - Sculpture
参考博文:Sculpture (UVa 12171) bfs + 离散化
代码:
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 50+5;
const int maxl = 1000+1;
int xl[maxn],yl[maxn],zl[maxn];//最小的x,y,z坐标
int xr[maxn],yr[maxn],zr[maxn];//最大的x,y,z坐标
int gra[maxn<<1][maxn<<1][maxn<<1];//离散化后的数组,下标是x,y,z坐标
int xx[maxn<<1],yy[maxn<<1],zz[maxn<<1];//存储一个长方体最大和最小的x,y,z坐标,用于离散化区域
int xcnt,ycnt,zcnt;
//表示三个维度的增减方向
int dx[6] = {1,-1,0,0,0,0};
int dy[6] = {0,0,1,-1,0,0};
int dz[6] = {0,0,0,0,1,-1};
struct Point{
int x,y,z;
Point(int x = 0,int y = 0,int z = 0) :
x(x),y(y),z(z) {}
//判断坐标是否在范围内
bool valid()const{
if(0<=x && 0<=y && 0<=z && x<xcnt-1 && y<ycnt-1 && z<zcnt-1) return true;
else return false;
}
//判断是否是建筑物区域
bool solid()const{
return gra[x][y][z] == 1;
}
//将区域设置为已经遍历过
void Setvis()const{
gra[x][y][z] = 2;
}
//判断区域是否已经遍历过
bool Getvis()const{
return gra[x][y][z] ==2;
}
//根据方向i获取邻居区域
Point neighbour(int i)const{
return Point(x+dx[i],y+dy[i],z+dz[i]);
}
//获取该区域的体积
int volume()const{
return (xx[x+1]-xx[x])*(yy[y+1]-yy[y])*(zz[z+1]-zz[z]);
}
//获取该区域的面积
int area(int dir)const{
if(dx[dir] != 0) return (yy[y+1]-yy[y])*(zz[z+1]-zz[z]);
else if(dy[dir] != 0) return (xx[x+1]-xx[x])*(zz[z+1]-zz[z]);
else return (xx[x+1]-xx[x])*(yy[y+1]-yy[y]);
}
};
//寻找数组num中,tar的下标
int ID_find(int *num,int len,int tar){
return lower_bound(num,num+len,tar)-num;
}
void floodfill(int &V,int &S){
Point c;
c.Setvis();//标记已经遍历过
queue<Point> que;
que.push(c);
while(!que.empty()){
Point first = que.front();
que.pop();
V += first.volume();//累加该区域的体积
for(int i = 0;i < 6;i++){
Point Next = first.neighbour(i);//获取邻居区域
if(Next.valid()){//该区域在规定范围内
if(Next.solid()){//如果该区域是建筑物内
S += first.area(i);//累加该区域的外表面积
}
else if(!Next.Getvis()){//没有遍历到的空气区域
Next.Setvis();
que.push(Next);
}
}
}
}
V = maxl*maxl*maxl-V;
}
//用于去重操作
void Unique(int *num,int cnt,int &ccnt){
sort(num,num+cnt);
ccnt = unique(num,num+cnt)-num;
}
int main()
{
#ifdef ONLINE_JUDGE
#else
freopen("input.txt","r",stdin);
#endif // ONLINE_JUDGE
int iCase;
scanf("%d",&iCase);
while(iCase--){
int n;
scanf("%d",&n);
int cnt = 2;
//相当于在建筑物周围加入空气,0一定最小,maxl一定最大,建筑物的坐标一定在二者之间
xx[0] = yy[0] = zz[0] = 0;
xx[1] = yy[1] = zz[1] = maxl;
for(int i = 0;i < n;i++){
scanf("%d%d%d%d%d%d",&xl[i],&yl[i],&zl[i],&xr[i],&yr[i],&zr[i]);
xr[i] += xl[i],yr[i] += yl[i],zr[i] += zl[i];
xx[cnt] = xl[i],yy[cnt] = yl[i],zz[cnt++] = zl[i];
xx[cnt] = xr[i],yy[cnt] = yr[i],zz[cnt++] = zr[i];
}
//去重操作,xx变为去重后的坐标数组,xcnt变为去重后的数组大小
Unique(xx,cnt,xcnt);
Unique(yy,cnt,ycnt);
Unique(zz,cnt,zcnt);
memset(gra,0,sizeof(gra));
for(int i = 0;i < n;i++){
//X1代表x1[i]在xx中的下标,说明将区域离散化为了点
int X1 = ID_find(xx,xcnt,xl[i]),X2 = ID_find(xx,xcnt,xr[i]);
int Y1 = ID_find(yy,ycnt,yl[i]),Y2 = ID_find(yy,ycnt,yr[i]);
int Z1 = ID_find(zz,zcnt,zl[i]),Z2 = ID_find(zz,zcnt,zr[i]);
for(int X = X1;X < X2;X++){ //这里一定是 < ,因为是以点代体,如果点到了边界,体就出去了
for(int Y = Y1;Y < Y2;Y++){
for(int Z = Z1;Z < Z2;Z++){
gra[X][Y][Z] = 1;//将建筑物中的区域全赋值为1,以标记
}
}
}
}
int V = 0,S = 0;
floodfill(V,S);
printf("%d %d\n",S,V);
}
return 0;
}
题目链接:1572 - Self-Assembly
参考博文:UVA ~ 1572 ~ Self-Assembly (拓扑排序)
代码:
#include
#include
#include
#include
#include
#include
using namespace std;
const int bias = 26;
int a[10], G[100][100], in_degree[100];
set<int> Set;
//使用队列的拓扑排序
bool toposort()
{
queue<int> q;
set<int> ans;
set<int>::iterator it;
for(it=Set.begin(); it!=Set.end(); it++)
{
if(in_degree[*it]==0)
{
q.push(*it);
}
}
while(!q.empty())
{
int u = q.front(); q.pop();
ans.insert(u);
for(it=Set.begin(); it!=Set.end(); it++)
{
if(G[u][*it])
{
G[u][*it] = 0;
in_degree[*it]--;
if(in_degree[*it]==0)
q.push(*it);
}
}
}
if(ans.size()==Set.size()) return 1;
else return 0;
}
void Init()
{
Set.clear();
memset(G, 0, sizeof(G));
memset(in_degree, 0, sizeof(in_degree));
}
int main()
{
int n;
char s[10];
while(scanf("%d", &n)!=EOF)
{
Init();
for(int i=0; i<n; i++)
{
memset(a, -1, sizeof(a));
scanf("%s", s);
//提取出编号
for(int i=1; i<=7; i+=2)
{
if(s[i]=='-')
a[i/2] = s[i-1]-'A';
else if(s[i]=='+')
a[i/2] = s[i-1]-'A'+bias;
}
//建立有向图
for(int i=0; i<4; i++)
{
if(a[i]<0) continue;//表明该位置是00
for(int j=0; j<4; j++)
{
if(a[j]<0 || i==j) continue;
int ajb = (a[j]+bias)%(2*bias);//a[j]可以相连的字符编号
if(G[a[i]][ajb]) continue;
G[a[i]][ajb] = 1;
in_degree[ajb]++;
Set.insert(a[i]), Set.insert(ajb);//存储所有出现的结点
}
}
}
if(toposort())
printf("bounded\n");
else
printf("unbounded\n");
}
return 0;
}
题目链接:1599 - Ideal Path
代码:
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define MAXN 100000+5
#define MAXN2 1000000000+5;
// 因为两个结点之间可能不止一条边,因此就不能以普通的邻接矩阵来存储图
// 使用vector将所有结点的邻接点和相应的连接边存起来,下标是一一对应的
vector<int> g[MAXN];
vector<int> c[MAXN];
// d数组保存每个结点到终点的距离
// ans数组保存最短路径上的每条边的权值
int d[MAXN],ans[MAXN];
bool vis[MAXN];
// 第一遍BFS,从终点开始到起点结束
// 为每个点标记它离终点的距离
// 这样就能够保证从起点开始再来一次BFS时
// 所选择的点都是处在最短路径上的
void bfs(int x)
{
queue<int> q;
q.push(x);
while(q.size())
{
int u=q.front();
q.pop();
int len=g[u].size();
for(int i=0;i<len;i++)
{
int v=g[u][i];
if(v==1)
{
d[v]=d[u]+1;
return;
}
else if(d[v]>d[u]+1)// 当前点的所有邻接点,到终点的距离都要+1
{
d[v]=d[u]+1;
q.push(v);
}
}
}
}
// 第二遍BFS,从起点开始
// BFS中,要在某结点被加入进队列之后就把该结点置为已访问
// 如果在出队时将该结点置为已访问,就可能把已经在队列里的邻接点又加入队列,导致超时
void bfs2()
{
queue<int> q;
q.push(1);
while(q.size())
{
int u=q.front();
q.pop();
if(d[u]==0) return;
int len=c[u].size();
int min_color=MAXN2;
// 对于当前扩展到的每个结点(即出队结点)
// 遍历其邻接点,且邻接点需比当前点离终点的距离小1,以确保它在最短路径上
// 找出连接边权值的最小值
for(int i=0;i<len;i++)
{
int v=g[u][i];
if(d[v]==d[u]-1)
{
min_color=min(min_color,c[u][i]);
}
}
// t即为保存最短边权值序列的数组的索引
int t=d[1]-d[u];
ans[t]=min(ans[t],min_color); //更新
// 将当前点所有满足三个条件的邻接点加入队列
// 条件为:未被访问过,离终点距离小1,连接边权值等于上面找到的最小值
for(int i=0;i<len;i++)
{
int v=g[u][i];
if(vis[v]==false && d[v]==d[u]-1 && c[u][i]==min_color) //这个也是细节
{
q.push(v);
vis[v]=true;
}
}
}
return ;
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=0;i<MAXN;i++)
{
g[i].clear();
c[i].clear();
}
for(int i=1;i<=m;i++)
{
int a,b,c1;
scanf("%d%d%d",&a,&b,&c1);
g[a].push_back(b);
g[b].push_back(a);
c[a].push_back(c1); //从a出发颜色可以是c1,从b出发的颜色也可以是c1
c[b].push_back(c1);
}
for(int i=0;i<=n;i++)
{
d[i]=MAXN;
ans[i]=MAXN2;
vis[i]=false;
}
d[n]=0;
bfs(n);
bfs2();
printf("%d\n", d[1]);
printf("%d",ans[0]);
for(int i=1;i<d[1];i++)
{
printf(" %d",ans[i]);
}
printf("\n");
}
return 0;
}
题目链接:506 - System Dependencies
参考博文:System Dependencies
代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 10000010;
//depend[x]和be_depended[x]分别表示组件x所依赖的组件列表和依赖于x的组件列表
vector<int> depend[maxn], be_depended[maxn];
vector<int> installed;
map<string, int> item;
string name[maxn];
int status[maxn];//0表示组件x未安装,1表示显示安装,2表示隐式安装
int cnt;
//首先,维护一个组建的名字列表——可以把输入中的组件名全部转化为整数编号。
//此处可以使用一个map记录出现过的组件名及其编号,使用字符串数组name方便记录编号对应的组件名。
int ID(string It)
{
if(item.count(It)) return item[It];
item[It] = ++cnt;
name[cnt] = It;//根据编号找对应组件的名字
return cnt;
}
void install(int it, bool toplevel)//toplevel区分显、隐式安装
{
if(!status[it])//it还没有安装
{
for(int i = 0; i < depend[it].size(); i++)
{
install(depend[it][i], false); //隐式安装
}
cout << " Installing " << name[it] << endl;
//赋值显式安装和隐式安装
status[it] = toplevel ? 1 : 2;
installed.push_back(it);
}
}
bool needed(int it)
{
for(int i = 0; i < be_depended[it].size(); i++)
{
if(status[be_depended[it][i]]) return true; //组件被其他组件依赖,且该组件还在
}
return false;
}
void Remove(int it, bool toplevel)
{
if((toplevel || status[it] == 2) && !needed(it))//(显式指定删除||隐式安装)&&不被依赖
{
status[it] = 0;//卸载
installed.erase(find(installed.begin(), installed.end(), it));//从已安装名单中移除
cout << " Removing " << name[it] << endl;
for(int i = 0; i < depend[it].size(); i++)//卸载其依赖包
{
Remove(depend[it][i], false);
}
}
}
int main()
{
cnt = 0;
string com, item1, other;
getline(cin, com);
while(1)
{
cout << com << endl;
istringstream line(com);
line >> com;
if(com == "END") break;
if(com == "DEPEND")
{
line >> item1;
int id1 = ID(item1), id2;
while(line >> other)
{
id2 = ID(other);
depend[id1].push_back(id2);//id1依赖id2
be_depended[id2].push_back(id1);//id2被id1依赖
}
}
else if(com == "INSTALL")
{
line >> item1;
int id = ID(item1);
if(status[id])//组件已经安装
cout << " " << name[id] << " is already installed." << endl;
else
install(id, true); //显式安装
}
else if(com == "REMOVE")
{
line >> item1;
int id = ID(item1);
if(!status[id])//没有安装
cout << " " << name[id] << " is not installed." << endl;
else if(needed(ID(item1)))//存在其他包依赖它
cout << " " << name[id] << " is still needed." << endl;
else
Remove(id, true); //显式卸载
}
else if(com == "LIST")
{
for(int i = 0; i < installed.size(); i++)
cout << " " << name[installed[i]] << endl;
}
getline(cin, com);
}
return 0;
}
题目链接:11853 - Paintball
参考博文:UVA 11853 Paintball
#include
#include
#include
#include
#include
using namespace std;
struct Node
{
int x, y, r;
Node(int x=-1, int y=-1, int r=-1):x(x), y(y), r(r){}
bool operator < (const Node &A) const
{
if(y==A.y)
return x<A.x;
else
return y>A.y;
}
};
set<Node> Set;
int vis[1005][1005];
double Wn, En;
//判断连个区域是否相连
bool check2(Node u, Node v)
{
double dis = sqrt((u.x-v.x)*(u.x-v.x)+(u.y-v.y)*(u.y-v.y));
double dis2 = (double)(u.r+v.r);
return dis <= dis2;
}
bool dfs(Node u)
{
vis[u.x][u.y] = 1;
if(u.x-u.r<=0)//更新西边进入的位置
{
double d = (double)u.y-sqrt(u.r*u.r-u.x*u.x);
Wn = min(Wn, d);
}
if(u.x+u.r>=1000)//更新东边出的位置
{
double d = (double)u.y-sqrt(u.r*u.r-(1000-u.x)*(1000-u.x));
En = min(En, d);
}
if(u.y-u.r<=0) return 1;//到达了最下面
set<Node>:: iterator it;
for(it=Set.begin(); it!=Set.end(); it++)//寻找相交的区域,递归遍历
{
int x = (*it).x, y = (*it).y, r = (*it).r;
if(!vis[x][y] && check2(u, *it))
{
if(dfs(*it)) return 1;
}
}
return 0;
}
int main()
{
int T, x, y, r;
while(cin >> T)
{
Set.clear();
while(T--)
{
cin >> x >> y >> r;
Set.insert(Node(x, y, r));
}
memset(vis, 0, sizeof(vis));
int flag = 1;
Wn = 1000, En = 1000;//西面最北的进入位置,东面最北的进入位置
set<Node>::iterator it;
for(it=Set.begin(); it!=Set.end(); it++)
{
int x = (*it).x, y = (*it).y, r = (*it).r;
if(y+r>=1000 && !vis[x][y])//选择包含最上界的未遍历的区域作为出发点
{
if(dfs(*it))
{
flag = 0;
}
}
}
if(!flag) printf("IMPOSSIBLE\n");
else printf("%.2f %.2f %.2f %.2f\n", 0.0, Wn, 1000.0, En);
}
return 0;
}
题目链接:673 - Parentheses Balance
代码:
#include
#include
#include
#include
using namespace std;
int main()
{
stack<char> stc;
string s;
int T;
cin >> T;
getchar();
while(T--)
{
getline(cin, s);//因为有空格和空字符串,所以按行输入
int len = s.size();
if(len==0)//空字符串
{
cout << "Yes" << endl;
continue;
}
int flag = 1;
//按栈来找对应的括号
for(int i=0; i<len; i++)
{
if(s[i]=='(' || s[i]=='[')
stc.push(s[i]);
else if(s[i]==')')
{
if(stc.size()==0 || stc.top()!='(')
{
flag = 0;
break;
}
stc.pop();
}
else if(s[i]==']')
{
if(stc.size()==0 || stc.top()!='[')
{
flag = 0;
break;
}
stc.pop();
}
else//其余的输入字符,均为错误
{
flag = 0;
break;
}
}
if(flag && stc.empty())//正常完成且括号完全匹配
cout << "Yes" << endl;
else
cout << "No" << endl;
while(!stc.empty()) stc.pop();//清空栈
}
return 0;
}
题目链接:712 - S-Trees
代码:
#include
#include
#include
#include
#include
#include
using namespace std;
int n, m;
string f, s, ans, vva;
vector<int> v;//存储每层的xi顺序
int main()
{
int kase = 1;
while(cin >> n && n)
{
v.clear();
ans = "";
for(int i=0; i<n; i++)
{
cin >> f;
int l = 0;
for(int j=1; j<f.size(); j++)
l = l*10+f[j]-'1';
v.push_back(l);//将xi转换为下标存储,与问题输入的下标对应起来
}
cin >> s;
cin >> m;
for(int i=0; i<m; i++)
{
cin >> vva;
int a = vva.size()-1;
int len = pow(2, a), id = 0;//len是当前子树的叶节点数量的一半
for(int j=0; j<v.size(); j++)//与二进制等效
{
if(vva[v[j]]=='1')//当为1时,加一半子树叶子节点
id += len;
else//当为0时,下标不变
id += 0;
len /= 2;//子树变小,叶节点数目减半
}
ans += s[id];
}
printf("S-Tree #%d:\n", kase++);
printf("%s\n\n", ans.c_str());
}
return 0;
}
题目链接:536 - Tree Recovery
参考博文:acm之旅–树
代码:
#include
#include
#include
#include
using namespace std;
string in, pre, post;
int pos;
//根据前序和中序得出后序的函数
void rec(int l, int r)
{
if(l>=r) return;
char v = pre[pos++];
int m = in.find(v);
rec(l, m);
rec(m+1, r);
post += v;//后序
}
int main()
{
while(cin >> pre)
{
cin >> in;
post = "", pos = 0;
rec(0, pre.size());
printf("%s\n", post.c_str());
}
return 0;
}
题目链接:439 - Knight Moves
代码:
#include
#include
#include
#include
using namespace std;
char st[5], ed[5];
struct Node
{
int r, c, step;//step记录从起始点到当前位置的步数
Node(int r=-1, int c=-1, int step=-1):r(r), c(c), step(step){}
};
Node s, e;
int vis[15][15];
int dx[10] = {1, -1, 2, -2, 1, -1, 2, -2};
int dy[10] = {2, 2, 1, 1, -2, -2, -1, -1};
//bfs模板
int bfs(Node u)
{
memset(vis, 0, sizeof(vis));
queue<Node> q;
q.push(u);
vis[u.r][u.c] = 1;
while(!q.empty())
{
Node v = q.front(); q.pop();
if(v.r==e.r && v.c==e.c)
{
return v.step;
}
for(int i=0; i<8; i++)
{
int r = v.r+dx[i], c = v.c+dy[i];
if(r>=0 && r<8 && c>=0 && c<8 && !vis[r][c])
{
vis[r][c] = 1;
q.push(Node(r, c, v.step+1));
}
}
}
}
int main()
{
while(scanf("%s%s", st, ed)!=EOF)
{
s = Node(st[1]-'1', st[0]-'a', 0);//起始点
e = Node(ed[1]-'1', ed[0]-'a');//终止点
int steps = bfs(s);
printf("To get from %s to %s takes %d knight moves.\n", st, ed, steps);
}
return 0;
}
题目链接:1600 - Patrol Robot
参考博文:uva1600 Patrol Robot(不同的BFS最短路)
UVA1600-Patrol Robot(BFS进阶)
方法一:
重点在于,如何处理连续穿越k个障碍,有可能物体从两条路到达一个位置,虽然有一条路长度较长,但是可以穿越更多障碍,而另一条虽然先到达,但是因为可以穿越的障碍少,使得无法到达目的地
。一种处理方法是:增加一个数组用来存储当前结点还能跨过几个障碍。可以知道,在到达同一个位置时,在步数比之前步数要大的情况下,如果还可以跨越的障碍物没有之前的要多,那么就一点优势就没有了,就可以把这种情况减枝掉
。因此每到一个结点,判断当前走法所剩的k值,如果小于当前结点的值(即之前走法有更大的k),就舍弃。代码:
#include
#include
#include
#include
#include
using namespace std;
int m, n, k;
int leave[25][25];//记录当前到达位置还可以越过最大的障碍数
int vis[25][25];//记录地图
struct Node
{
int r, c, step, leave;//step记录从起始点到当前位置的步数,leave记录还可以越过多少个障碍
Node(int r=-1, int c=-1, int step=-1, int leave=-1):r(r), c(c), step(step), leave(leave){}
};
//右、左、下、上
int dr[5] = {0, 0, 1, -1};
int dc[5] = {1, -1, 0, 0};
int bfs(Node u)
{
memset(leave, -1, sizeof(leave));
queue<Node> q;
q.push(u);
vis[u.r][u.c] = -1;
while(!q.empty())
{
Node v = q.front(); q.pop();
if(v.r==m && v.c==n) return v.step;
for(int i=0; i<4; i++)
{
int r = v.r+dr[i], c = v.c+dc[i];
if(r<1 || r>m || c<1 || c>n) continue;//出界
if(leave[r][c]>=v.leave) continue;//可以跨越的障碍物越多越好
else leave[r][c] = v.leave;
if(vis[r][c]==0)//0值
q.push(Node(r, c, v.step+1, k));
else if(v.leave)//1值并且还可以跨越障碍
q.push(Node(r, c, v.step+1, v.leave-1));
}
}
return -1;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &m, &n);
scanf("%d", &k);
for(int i=1; i<=m; i++)
{
for(int j=1; j<=n; j++)
{
cin >> vis[i][j];
}
}
int steps = bfs(Node(1, 1, 0, k));
printf("%d\n", steps);
}
return 0;
}
方法二:
因此,我的改进方法是如果当前是第一个到达该位置的,那么就将经过更多(包括与当前情况一样的)障碍物的vis数组全部赋值为1,即以后只能在穿越更少的障碍物的情况下访问该位置(因为走的步数更多)
。代码:
#include
#include
#include
#include
#include
using namespace std;
struct Point{
int x,y,time;
int layer;//连续走过的障碍数目
Point(int x = 0,int y = 0,int time = 0,int layer = 0) :
x(x),y(y),time(time),layer(layer) {}
};
const int maxn = 22;
int gra[maxn][maxn];
int vis[maxn][maxn][maxn];
int n,m,k;
int dx[4] = {1,-1,0,0};
int dy[4] = {0,0,-1,1};
int bfs(){
queue<Point> que;
que.push(Point(1,1,0,0));
memset(vis,0,sizeof(vis));
vis[1][1][0] = 1;
while(!que.empty()){
Point first = que.front();que.pop();
if(first.x==n && first.y==m) return first.time;//到达目的地
int xx,yy;
for(int i = 0;i < 4;i++){
xx = first.x+dx[i],yy = first.y+dy[i];
if(1<=xx && 1<=yy && xx<=n && yy<=m){//在界内
int layer = first.layer;
if(gra[xx][yy]) layer++;//当前位置时障碍
else layer = 0;//当前位置不是障碍
if(layer<=k && !vis[xx][yy][layer]){//在连续穿越了layer个障碍到达xx,yy位置
//vis[xx][yy][layer] = 1;//原代码
//改进代码
for(int j=layer; j<=k; j++)
vis[xx][yy][j] = 1;
que.push(Point(xx,yy,first.time+1,layer));
}
}
}
}
return -1;
}
int main()
{
//freopen("input.txt","r",stdin);
int iCase;
scanf("%d",&iCase);
while(iCase--){
scanf("%d%d",&n,&m);
scanf("%d",&k);
for(int i = 1;i <= n;i++){
for(int j = 1;j <= m;j++){
scanf("%d",&gra[i][j]);
}
}
printf("%d\n",bfs());
}
return 0;
}
题目链接:12166 - Equilibrium Mobile
代码:
#include
#include
#include
#include
#include
#include
#include
using namespace std;
string s;
stack<char> stc;//记录当前结点的深度
set<int> Set;//记录叶子数值,是m的键
map<int, int> m;//记录叶子数值对应的个数
void solve(int len)
{
Set.clear();
m.clear();
while(!stc.empty()) stc.pop();
int sum = 0, layer = 0;
//求出树的最大深度layer
for(int i=0; i<len; i++)
{
if(s[i]=='[')
stc.push(s[i]);
else if(s[i]==']')
stc.pop();
if(stc.size()>layer) layer = stc.size();
}
while(!stc.empty()) stc.pop();
//记录所有砝码质量的个数
for(int i=0; i<len; i++)
{
if(s[i]=='[')
stc.push(s[i]);
else if(s[i]==']')
stc.pop();
else if(isdigit(s[i]))
{
sum++;//记录有多少个数字结点
int n = s[i]-'0';
int t = i+1;
while(t<len && isdigit(s[t]))
n = n*10+s[t++]-'0';
i = t-1;
int d = stc.size();
n = n/pow(2, layer-d);//该数字结点对应的叶子结点的数值
if(Set.count(n)) m[n] = m[n]+1;
else m[n] = 1, Set.insert(n);
}
}
int Max = 0;
//求最多的叶子数值个数
set<int>::iterator it;
for(it=Set.begin(); it!=Set.end(); it++)
{
int t = *it;
if(Max<m[t]) Max = m[t];
}
printf("%d\n", sum-Max);
}
int main()
{
#ifdef ONLINE_JUDGE
#else
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
int T;
cin >> T;
while(T--)
{
cin >> s;
solve(s.size());
}
}
题目链接:10410 - Tree Reconstruction
参考博文:随缘&不屈UVA10410-Tree Reconstruction(BFS序和DFS序的性质)
UVA10410 TreeReconstruction 树重建 (dfs,bfs序的一些性质,以及用栈处理递归 )
uva 10410 - Tree Reconstruction(栈)
代码:
#include
using namespace std;
const int MAX = 1005;
vector<int> G[MAX];
int pos[MAX];//
int main()
{
int n, t;
while(scanf("%d", &n)!=EOF)
{
int x;
//BFS
for(int i=1; i<=n; i++)
{
scanf("%d", &t);
pos[t] = i;//记录bfs中每一个元素对应的位置
G[i].clear();
}
int root;
scanf("%d", &root);
stack<int> stc;
stc.push(root);
for(int i=1; i<n; i++)
{
scanf("%d", &t);
while(1)
{
int u = stc.top();
if(pos[u]+1<pos[t] || (pos[u]+1 == pos[t] && u > t) || u==root)//子节点||根节点
{
G[u].push_back(t);
stc.push(t);
break;
}
else stc.pop();
}
}
for(int i=1; i<=n; i++)
{
printf("%d:", i);
for(int j=0; j<G[i].size(); j++)
{
if(j) printf(" ");
printf(" %d", G[i][j]);
}
printf("\n");
}
}
return 0;
}
题目链接:12118 - Inspector’s Dilemma
参考博文:UVa 12118 - Inspector’s Dilemma
代码:
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAX = 1005;
vector<int> G[MAX];//存选定的路径
set<int> Set;//存选定路径包括的点
//vis表示遍历数组,degree表示结点的度的数组,sum_deg表示每个连通块中需要额外走的路径个数之和,sum_num表示连通块个数
int vis[MAX], degree[MAX], sum_deg, sum_num;
//bfs统计连通图中的奇数断定个数
void bfs(int u)
{
int cnt = 0;
queue<int> q;
q.push(u);
vis[u] = 1;
while(!q.empty())
{
int v = q.front(); q.pop();
if(degree[v]%2) cnt++;
for(int i=0; i<G[v].size(); i++)
{
if(!vis[G[v][i]])
{
vis[G[v][i]] = 1;
q.push(G[v][i]);
}
}
}
if(cnt>0)
sum_deg += (cnt-1)/2;
}
void Init()
{
memset(vis, 0, sizeof(vis));
memset(degree, 0, sizeof(degree));
Set.clear();
}
int main()
{
#ifdef ONLINE_JUDGE
#else
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
int V, E, T, a, b, kase = 1;
while(scanf("%d%d%d", &V, &E, &T) && (V+E+T))
{
if(E==0)//注意数据范围
{
printf("Case %d: %d\n", kase++, 0);
continue;
}
Init();
for(int i=0; i<E; i++)
{
scanf("%d%d", &a, &b);
G[a].push_back(b);
G[b].push_back(a);
Set.insert(a);
Set.insert(b);
degree[a]++;
degree[b]++;
}
sum_deg = 0, sum_num = 0;
set<int>::iterator it;
for(it=Set.begin(); it!=Set.end(); it++)
{
if(!vis[*it]) bfs(*it), sum_num++;
}
printf("Case %d: %d\n", kase++, (sum_deg+E+sum_num-1)*T);
for(it=Set.begin(); it!=Set.end(); it++)
{
G[*it].clear();
}
}
return 0;
}