# PAT甲级题

1001 A+B Format (20)

1002 A+B for Polynomials (25)

1003 Emergency (25)（最短路）

#include <bits/stdc++.h>
using namespace std;
const int maxn_v = 500 + 5;
const int INF = 0x3f3f3f3f;
typedef pair<int, int>pii;

struct Edge{int to, w;};
vector<Edge>G[maxn_v];

int people[maxn_v], dis[maxn_v], vis[maxn_v], path[maxn_v], gather[maxn_v];
void dijkstra(int vs, int es, int s, int t)
{
for(int i = 0; i < vs; i++)    dis[i] = INF, vis[i] = 0, path[i] = 1, gather[i] = people[i];
priority_queue<pii, vector<pii>, greater<pii>>que;

dis[s] = 0;
que.push({0, s});

while(que.size())
{
pii cur = que.top();que.pop();
int u = cur.second, w = cur.first;
if(vis[u])  continue;
vis[u] = 1;
for(auto o : G[u])
{
if(dis[u] + o.w < dis[o.to])
{
dis[o.to] = dis[u] + o.w;
que.push({o.to, dis[o.to]});
path[o.to] = path[u];

if(gather[o.to] < gather[u] + people[o.to])
{
gather[o.to] = gather[u] + people[o.to];
}
que.push({dis[o.to], o.to});
}
else if(dis[u] + o.w == dis[o.to])
{
path[o.to] += path[u];
if(gather[o.to] < gather[u] + people[o.to])
{
gather[o.to] = gather[u] + people[o.to];
}
}
}
}
cout << path[t] <<  " " << gather[t] << endl;
}

int main()
{
int vs, es, s, t;
scanf("%d%d%d%d", &vs, &es, &s, &t);
for(int i = 0; i < vs; i++)    scanf("%d", &people[i]);
for(int i = 0; i < es; i++)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
G[u].push_back({v, w});
G[v].push_back({u, w});
}
dijkstra(vs, es, s, t);
return 0;
}


1004 Counting Leaves (30)（dfs）

n这么小，直接搜就行了

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 100 +5;
typedef pair<int, int>pii;

int maxlv;
int level[maxn];
int cnt[maxn];
vector<int>G[maxn];

void dfs(int cur, int lv)
{
level[cur] = lv;
maxlv = max(maxlv, lv);
if(G[cur].size() == 0)  cnt[lv]++;//如果它没有孩子，说明它这一层没有孩子的结点数++
for(auto o : G[cur])   dfs(o, lv + 1);
}

int main()
{
int n, m;
scanf("%d%d", &n, &m);
while(m--)
{
int pa, num;
scanf("%d%d", &pa, &num);
while(num--)
{
int ch;
scanf("%d", &ch);
G[pa].push_back(ch);
}
}
maxlv = 0;
dfs(1, 0);
for(int i = 0; i <= maxlv; i++)
{
printf("%d%c", cnt[i], i == maxlv ? '\n' : ' ');
}
return 0;
}

1005 Spell It Right (20)

1006 Sign In and Sign Out (25)

1007 Maximum Subsequence Sum (25)（最大字段和）

1008 Elevator (20)

1009 Product of Polynomials (25)

1011 World Cup Betting (20)

1012 The Best Rank (25)

1013 Battle Over Cities (25)（并查集or深搜）

我们画几个图就很容易明白，n个结点如果想要联通，必然至少需要n-1条边。那么如果是n个块（一个块有若干个联通的结点）呢，是不是也是如此。这里就有一个连通分量的概念。然后我们怎么去看有几个块呢，显然并查集和dfs都是极好的。
这里只讲dfs，其实题目很简单，就是最入门的dfs题，想一下刚学dfs时候的八连通，四联通的题目，只需要dfs和vis标记即可。

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1000 +5;
typedef pair<int, int>pii;

int attack;
int vis[maxn];
vector<int>G[maxn];

void dfs(int cur)
{
vis[cur] = 1;
for(auto o : G[cur])    if(vis[o] == 0 && o != attack) dfs(o);
}

int main()
{
int vs, es, query;
scanf("%d%d%d", &vs, &es, &query);

while(es--)
{
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);//无向图建图
G[v].push_back(u);
}

while(query--)
{
int x;
scanf("%d", &x);
attack = x;
//计算联通分量
memset(vis, 0, sizeof(vis));
int scc = 0;
for(int i = 1; i <= vs; i++)
{
if(i == attack || vis[i]) continue;//如果已经被攻占，或者已经被dfs过了，跳过
dfs(i);
scc++;
}
printf("%d\n", scc - 1);
}
return 0;
}

1014 Waiting in Line (30)（挺繁琐的模拟）

n个窗口，每个窗口可以排m人。有k位顾客需要办理业务，给出了每个客户的办理业务时间。银行在8点开始服务，如果窗口都排满了，客户就得在黄线外等候。如果有一个窗口用户服务结束，黄线外的客户就进来一个。如果有多个可选，选窗口id最小的。输出查询客户的服务结束时间。

1015 Reversible Primes (20)

1016 Phone Bills (25)（繁琐的模拟）

n个人的通话记录,然后给你每个时间段的话费单价,让你求出每个用户每个月的电话账单

1017 Queueing at Bank (25)（繁琐的模拟）

1018 Public Bike Management (30)

1019 General Palindromic Number (20)

1020 Tree Traversals (25)

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 500 +5;

typedef pair<int, int>pii;
int post[35], in[35], lch[35], rch[35];
int build(int L1, int R1, int L2, int R2)//in中序遍历 [L1，R1], post后序遍历[L2,R2]
{
if(L1 > R1) return -1;
int root = post[R2];
int p = L1;
while(in[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 level_order(int root)//层序遍历
{
queue<int>que;
que.push(root);
while(que.size())
{
int cur = que.front();que.pop();
int lson = lch[cur], rson = rch[cur];
if(lson != -1)  que.push(lson);
if(rson != -1)  que.push(rson);
printf("%d%c", cur, que.size() ? ' ' : '\n');
}
}

int main()
{
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) scanf("%d", &post[i]);
for (int i = 0; i < n; i++) scanf("%d", &in[i]);
int root = build(0, n - 1, 0, n - 1);
level_order(root);
return 0;
}

1021 Deepest Root (25)

这是比前两个dfs稍微难一点的dfs。其实就是树的直径问题，求解树的直径，我们是使用dfs的方式，我们先从任意一个点dfs，找到深度最深的点，在开始dfs，找到深度最深的点，这个时候深度就是树的直径了。
dfs_scc就是找联通分块的函数，其实就是1013的翻版。
dfs_level就是用temp数组来保存深度最深的节点有哪些。然后挑任意一个点开始第二次dfs_level，temp数组即为答案。

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 10000 +5;

int maxLevel;
int vis[maxn];
int level[maxn];
vector<int>G[maxn];
vector<int>temp;

void dfs_scc(int cur)
{
vis[cur] = 1;
for(auto o : G[cur])    if(vis[o] == 0) dfs_scc(o);
}

void dfs_level(int cur, int pa, int lv)
{//深搜层数
level[cur] = lv;
if(lv > maxLevel)
{
maxLevel = lv;
temp.clear();
temp.push_back(cur);
}
else if(lv == maxLevel)
{
temp.push_back(cur);
}

for(auto o : G[cur])
{
if(o != pa)
{
dfs_level(o, cur, lv + 1);
}
}
}

int main()
{
int vs;
scanf("%d", &vs);
for(int i = 1; i < vs; i++)
{
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);//无向图建图10
G[v].push_back(u);
}

int scc = 0;
for(int i = 1; i <= vs; i++)
{
if(vis[i] == 0) dfs_scc(i), scc++;
}

if(scc != 1)
{
printf("Error: %d components\n", scc);
}
else
{
set<int>ans;
//第一次dfs
maxLevel = 0;
temp.clear();
memset(level, 0, sizeof(level));
dfs_level(1, -1, 0);
int root = temp[0];

for(auto o : temp)  ans.insert(o);

//第二次dfs
maxLevel = 0;
temp.clear();
memset(level, 0, sizeof(level));
dfs_level(root, -1, 0);
root = temp[0];

for(auto o : temp)  ans.insert(o);

for(auto o : ans)
{
printf("%d\n", o);
}
}
return 0;
}

1022 Digital Library (30)（繁琐的模拟）

1023 Have Fun with Numbers (20)

1024 Palindromic Number (25)

1025 PAT Ranking (25)（模拟模拟）

1026 Table Tennis (30)（挺繁琐的模拟）

1027 Colors in Mars (20)

1028 List Sorting (25)

1029 Median (25)

1030 Travel Plan (30)

1031 Hello World for U (20)

1032 Sharing (25)

1033 To Fill or Not to Fill (25)

1034 Head of a Gang (30)

1036 Boys vs Girls (25)

1037 Magic Coupon (25)

1038 Recover the Smallest Number (30)

1039 Course List for Student (25)

1040 Longest Symmetric String (25)

1041 Be Unique (20)

1042 Shuffling Machine (20)

1043 Is It a Binary Search Tree (25)

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1000 +5;
typedef pair<int, int>pii;

struct node
{
int val;
node *left, *right;
node():left(NULL), right(NULL){}
};
int pre[maxn];//二叉搜索树的先序序列

bool judge(int L, int R, int k)
{
if(L >= R)  return true;
int p = L + 1;
if(k == 0)
{
while(p <= R && pre[p] < pre[L])  p++;//左子树小于根节点

for(int i = p; i <= R; i++)
{
if(pre[i] < pre[L]) return false;
}
}
else if(k == 1)//BST的镜像
{
while(p <= R && pre[p] >= pre[L]) p++;
for(int i = p; i <= R; i++)
{
if(pre[i] >= pre[L])    return false;
}
}

return judge(L + 1, p - 1, k) && judge(p, R, k);
}

node *build(int L, int R, int k)
{
if(L > R)  return NULL;

node *root = new node();
root->val = pre[L];

int p = L + 1;
if(k == 0)
{
while(p <= R && pre[p] < pre[L])  p++;//左子树小于根节点
}
else if(k == 1)//BST的镜像
{
while(p <= R && pre[p] >= pre[L]) p++;
}
root->left = build(L + 1, p - 1, k);
root->right = build(p, R, k);
return root;
}
void post_order(node *x, node *root)
{
if(x->left != NULL) post_order(x->left, root);
if(x->right != NULL)    post_order(x->right, root);

printf("%d", x->val);

if(x != root)   printf(" ");
else printf("\n");
}

void solve(int n)
{
if (judge(0, n - 1, 0))
{
puts("YES");
node *root = build(0, n - 1, 0);
post_order(root, root);
return ;
}
if (judge(0, n - 1, 1))
{
puts("YES");
node *root = build(0, n - 1, 1);
post_order(root, root);
return ;
}

puts("NO");
}

int main()
{
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%d", &pre[i]);
}
solve(n);

return 0;
}

1044 Shopping in Mars (25)

1045 Favorite Color Stripe (30)