标题
A - Bmail Computer Network
记录父节点,从n开始记录路径,倒着输出。
#include <iostream>
#include <stack>
using namespace std;
const int N = 200005;
int p[N];
int main()
{
int n;
stack<int> path;
cin >> n;
for(int i = 2; i <= n; i++)
{
cin >> p[i];
}
cout << 1;
while(n != 1)
{
path.push(n);
n = p[n];
}
while(!path.empty())
{
cout << " " << path.top();
path.pop();
}
return 0;
}
B - Protect Sheep
直接在每个羊的周围都放上狗
#include <iostream>
#include <stack>
#include <vector>
using namespace std;
struct Animal
{
int x;
int y;
};
char m[503][503];
int dic[4][2] = {{0,1}, {0,-1}, {1,0}, {-1,0}};
int main()
{
vector<Animal> sheep; // 每只羊的坐标
int r, c, cnt = 0, flag = 0;
cin >> r >> c;
for(int i = 1; i <= r; i++)
{
for(int j = 1; j <= c; j++)
{
scanf("%c", &m[i][j]);
if(m[i][j] == '\n')
{
j--; // j--和j++抵消了,下次重新输入到这个地方
}
else if(m[i][j] == 'S')
{
sheep.push_back({i,j});
}
else if(m[i][j] == 'W')
{
cnt++; // 狼的计数
}
}
}
if(cnt != 0) // 有狼,则有必要放狗
{
int ns = sheep.size(); // 遍历羊的坐标
for(int i = 0; i < ns; i++)
{
for(int j = 0; j < 4; j++) // 四个方向能放狗就都放上
{
int x = sheep[i].x + dic[j][0], y = sheep[i].y + dic[j][1];
if(m[x][y] == 'W') // 如果临近的就是狼,那就没法儿了,标记置1
{
flag = 1;
}
else if(m[x][y] == '.')
{
m[x][y] = 'D';
}
}
if(flag == 1)
{
break;
}
}
if(flag == 1) // 不能通过放狗把狼和羊隔开
{
printf("No\n");
}
}
if(flag == 0) // 如果没有狼,或者可以通过放狗把狼和羊隔开
{
printf("Yes\n");
for(int i = 1; i <= r; i++)
{
for(int j = 1; j <= c; j++)
{
printf("%c", m[i][j]);
}
printf("\n");
}
}
return 0;
}
C - King Escape
以皇后为原点的直角坐标系,如果国王的位置和目标位置在一个象限内,则YES,否则NO
#include <iostream>
using namespace std;
int main()
{
int n, ax, ay, bx, by, cx, cy, flag = 0;
cin >> n >> ax >> ay >> bx >> by >> cx >> cy;
// 四个象限
if(bx < ax && by < ay && cx < ax && cy < ay)
{
flag = 1;
}
if(bx > ax &&b y < ay && cx > ax && cy < ay)
{
flag = 1;
}
if(bx < ax && by > ay && cx < ax && cy > ay)
{
flag = 1;
}
if(bx > ax && by > ay && cx > ax && cy > ay)
{
flag = 1;
}
if(flag)
{
cout << "YES" << endl;
}
else
{
cout << "NO" << endl;
}
return 0;
}
D - Rook, Bishop and King
#include <iostream>
using namespace std;
int r1, r2, c1, c2;
int max(int a, int b)
{
return a > b?a:b;
}
// rook 在同一行或者同一列的话只需要一步,否则两步
int rook()
{
if(r1 == r2 || c1 == c2)
{
return 1;
}
return 2;
}
// bishop 同一对角线上走一步
// abs(abs(c1-c2) - abs(r1-r2)) % 2 == 1 则无法到达,画图可知
// 否则两步
int bishop()
{
if(r1 + c1 == r2 + c2 || r1 - c1 == r2 - c2)
{
return 1;
}
if(abs(abs(c1-c2) - abs(r1-r2)) % 2 == 1)
{
return 0;
}
return 2;
}
//先斜着走,再横着或竖着走,其实就是纵坐标之差和横坐标之差中大的那个
int king()
{
return max(abs(r1-r2), abs(c1-c2));
}
int main()
{
cin >> r1 >> c1 >> r2 >> c2;
cout << rook() << " " << bishop() << " " << king() << endl;
return 0;
}
E - Jumping on Walls
深搜,需要标记数组。
#include <iostream>
using namespace std;
int n, k, flag = 0;
string sl, sr;
bool f[2][110000];
/**
* 深搜
* 参数 lr 左还是右,0左,1右
* 参数 h 目前的高度
* 参数 hw 目前水的高度
*/
void dfs(int lr, int h, int hw)
{
if(h > n) flag = 1; // 可以出去
// 读取string里的字符,所以h-1
if(flag == 1 || f[lr%2][h-1] || hw >= h || h <= 0)
{
return;
}
if(lr%2 == 0 && sl[h-1] == 'X')
{
return;
}
if(lr%2 == 1 && sr[h-1] == 'X')
{
return;
}
hw++;
f[lr%2][h-1] = 1;
dfs(lr, h-1, hw); // 下
dfs(lr+1, h+k, hw); // 另一边
dfs(lr, h+1, hw); // 上
// 不知道为什么,顺序改成这个就不对了
// dfs(lr, h-1, hw);
// dfs(lr, h+1, hw);
// dfs(lr+1, h+k, hw);
}
int main()
{
cin >> n >> k >> sl >> sr;
dfs(0, 1, 0);
if(flag)
{
cout << "YES" << endl;
}
else
{
cout << "NO" << endl;
}
return 0;
}
F - Minimal Height Tree
题解
除了1所在的根节点以外,每一层的连续递增子序列的个数为
上一层的结点个数时,高度最小。
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <cstring>
#define INF 0x3f3f3f3f
using namespace std;
int t, n;
int main()
{
cin >> t;
while (t--)
{
int ans = 0, cnt = 1, cnt2 = 0, cnt3 = 0, p, a;
cin >> n >> p;
for (int i = 1; i < n; i++)
{
cin >> a;
if (a > p)
{
cnt2++; // 求连续递增的数的个数
}
else
{
cnt3++; // 求目前一层有几个连续递增的子序列
if (cnt == cnt3) // 如果连续递增子序列个数等于上一层的节点个数
{
// 当前结点为下一层的第一个节点
ans++; // 层数加1
cnt = cnt2 + cnt3 - 1; // 上一层的结点数更新为这一层
cnt2 = 1;
cnt3 = 0;
}
}
p = a;
}
cout << (++ans) << endl;
}
return 0;
}
Catch That Cow
广搜
#include <iostream>
#include <queue>
using namespace std;
typedef long long ll;
struct node
{
ll x;
ll cnt;
};
bool vis[100005] = {};
int main()
{
ll ans = 0, n, k;
queue<node> que;
cin >> n >> k;
node t = {n, 0};
que.push(t);
while (!que.empty())
{
node a = que.front();
que.pop();
if (a.x == k)
{
ans = a.cnt;
break;
}
else
{
a.cnt++;
ll b[3] = {a.x - 1, a.x + 1, 2 * a.x};
for (int i = 0; i < 3; i++)
{
if (b[i] < 0 || b[i] > 100000 || vis[b[i]])
{
continue;
}
vis[b[i]] = 1;
a.x = b[i];
que.push(a);
}
}
}
cout << ans << endl;
return 0;
}
H - Asteroids
匈牙利算法
#include <iostream>
#include <cstring>
using namespace std;
int n, k, x, y, cnt = 0;
bool m[505][505] = {};
bool vis[505] = {};
int p[505] = {};
bool match(int x)
{
for (int i = 1; i <= n; i++)
{
if (m[x][i] == 1 && !vis[i])
{
vis[i] = true;
if (p[i] == 0 || match(p[i]))
{
p[i] = x;
return true;
}
}
}
return false;
}
int main()
{
cin >> n >> k;
for (int i = 0; i < k; i++)
{
cin >> x >> y;
m[x][y] = 1;
}
for (int i = 1; i <= n; i++)
{
memset(vis, 0, sizeof(vis));
if (match(i))
{
cnt++;
}
}
cout << cnt << endl;
return 0;
}
I - Antenna Placement
拆点,最小点覆盖,匈牙利算法
#include <iostream>
#include <cstring>
using namespace std;
bool vis[500], bgraph[500][500];
int Map[42][12];
int h, w, cntv, p[500];
int match(int x)
{
for (int i = 1; i <= cntv; i++)
{
if (vis[i] == 0 && bgraph[x][i])
{
vis[i] = 1;
if (p[i] == 0 || match(p[i]))
{
p[i] = x;
return true;
}
}
}
return false;
}
int main()
{
int t;
cin >> t;
while (t--)
{
memset(bgraph, 0, sizeof(bgraph));
memset(Map, 0, sizeof(Map));
memset(p, 0, sizeof(p));
cin >> h >> w;
getchar();
cntv = 0;
for (int i = 1; i <= h; i++)
{
for (int j = 1; j <= w; j++)
{
Map[i][j] = (int)(getchar());
if (Map[i][j] == '*')
{
Map[i][j] = (++cntv);
if (Map[i-1][j])
{
bgraph[cntv][Map[i-1][j]] = 1;
bgraph[Map[i-1][j]][cntv] = 1;
}
if (Map[i][j - 1])
{
bgraph[cntv][Map[i][j-1]] = 1;
bgraph[Map[i][j-1]][cntv] = 1;
}
}
else
{
Map[i][j] = 0;
}
}
getchar();
}
int ans = 0;
for (int i = 1; i <= cntv; i++)
{
memset(vis, 0, sizeof(vis));
if (match(i))
{
ans++;
}
}
cout << cntv - ans / 2 << endl;
}
return 0;
}
J - Sorting It All Out
拓扑排序
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
int n, m, ans[30];
char a, b;
int topo(vector<int> *Map, int *num)
{
queue<int> q;
int c = 0, flag = 0, in[26];
for (int i = 0; i < 26; i++)
{
in[i] = num[i]; // 复制一份入度的统计数组以供拓扑排序
}
for (int j = 0; j < 26; j++)
{
if (Map[j].size() != 0 && num[j] == 0)
{
q.push(j);
}
}
while (!q.empty())
{
if (q.size() > 1)
{
flag = 1; // 多于一个点,则这几个点还排不出来,不能直接 break,因为还要判断有没有环
}
int x = q.front();
q.pop();
if (!flag)
{
ans[c++] = x; // 顺利的话把排好的存到数组里
}
for (size_t i = 0; i < Map[x].size(); i++) // 将x点和它的边隐藏
{
int t = Map[x][i];
in[t]--; // 依次减少入度
if (in[t] == 0)
{
q.push(t); // 入度为0则进入队列
}
}
}
for (int i = 0; i < 26; i++)
{
if (in[i])
{
return -1; // 存在环
}
}
if (flag || c < n)
{
return 0; // 未排好序
}
return 1; // 排好序了
}
int main()
{
while (scanf("%d%d", &n, &m) != EOF && n && m)
{
// num记录入度,cnt记录在哪里就已经排好序或者出现环,f接收拓扑排序结果
int num[26] = {}, cnt = 0, f = 0;
vector<int> Map[26];
getchar(); // 吞掉回车
for (int i = 1; i <= m; i++)
{
scanf("%c<%c", &a, &b);
if (!f) // 还没排好或者还未发现环则继续排
{
Map[a - 'A'].push_back(b - 'A');
num[b - 'A']++;
f = topo(Map, num);
cnt = i;
}
getchar(); // 吞掉回车
}
if (f == 1)
{
cout << "Sorted sequence determined after " << cnt << " relations: ";
for (int i = 0; i < n; i++)
{
cout << (char)(ans[i] + 'A');
}
cout << "." << endl;
}
else if (!f)
{
cout << "Sorted sequence cannot be determined." << endl;
}
else
{
cout << "Inconsistency found after " << cnt << " relations." << endl;
}
}
return 0;
}
K - Trees Made to Order
写的太冗长了,不想多说
#include <iostream>
#include <vector>
using namespace std;
int a[20] = {1}, b[20] = {1};
int Map1[20][20], Map2[20][20];
vector<int> vc[20];
struct Node
{
int x;
Node *l;
Node *r;
Node(int a): x(a)
{
l = NULL;
r = NULL;
}
};
void create(int i, int j, Node *p, int l, int r)
{
if (i <= 1)
{
return;
}
if (j != 0)
{
p->l = new Node(j);
if (j > 1)
{
int k, m;
for (k = 0; k < j && l >= Map2[j][k]; k++);
if (k == 0)
{
m = l;
}
else
{
m = l - Map2[j][k - 1];
}
create(j, k, p->l, m / a[j - k - 1], m % a[j - k - 1]);
}
}
j = i - j - 1;
if (j != 0)
{
p->r = new Node(j);
if (j > 1)
{
int k, m;
for (k = 0; k < j && r >= Map2[j][k]; k++);
if (k == 0)
{
m = r;
}
else
{
m = r - Map2[j][k - 1];
}
create(j, k, p->r, m / a[j - k - 1], m % a[j - k - 1]);
}
}
}
void Order(Node *T)
{
if (T == NULL)
{
return;
}
printf("(");
if (T->l != NULL)
{
Order(T->l);
}
printf("X");
if (T->r != NULL)
{
Order(T->r);
}
printf(")");
}
void release(Node *T)
{
if (T->l)
{
release(T->l);
}
if (T->r)
{
release(T->r);
}
delete T;
}
int main()
{
int n;
for (int i = 1; i < 19; i++)
{
for (int j = 0; j < i; j++)
{
Map1[i][j] = a[j] * a[i - j - 1]; //Map1[i][j]表示i个结点的二叉树左子树结点数位j时有多少种
Map2[i][i] += Map1[i][j];
Map2[i][j] = Map2[i][i];
}
a[i] += Map2[i][i]; //a[i],结点数为i的树的个数
b[i] = a[i] + b[i - 1];
}
while (scanf("%d", &n) != EOF && n)
{
Node *Tree = new Node(n);
int i = 0, j = 0, l = 0, r = 0, nextl = 0;
for (; i < 20 && n >= b[i]; i++);
nextl = n - b[i - 1]; //i为结点个数,在i个结点的树里排第nextl个,nextl范围[0,a[i]-1]
for (j = 0; j < i && nextl >= Map2[i][j]; j++);
//j为左子树结点个数,i-j-1是右子树结点个数
if (j == 0)
{
r = nextl;
}
else
{
r = nextl - Map2[i][j - 1];
}
l = r / a[i - j - 1];
r = r % a[i - j - 1];
create(i, j, Tree, l, r);
Order(Tree->l);
printf("X");
Order(Tree->r);
printf("\n");
release(Tree);
}
return 0;
}
L - Agri-Net
Kruskal
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
struct Node
{
int x;
int y;
int w;
bool operator< (Node b)
{
return w < b.w;
}
} edge[10000];
int p[105];
int Find(int x)
{
if (x != p[x])
{
p[x] = Find(p[x]);
}
return p[x];
}
int main()
{
int n;
while (cin >> n)
{
int cnt = 0, i = 0, j = 0, t;
for (i = 1; i <= n; i++)
{
p[i] = i;
}
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n; j++)
{
cin >> t;
if (i < j)
{
edge[++cnt].w = t;
edge[cnt].x = i;
edge[cnt].y = j;
}
}
}
sort(edge + 1, edge + cnt + 1, cmp);
ll ans = 0;
for (i = 1, j = 1; i < n && j <= cnt; j++)
{
int a = Find(edge[j].x), b = Find(edge[j].y);
if (a != b)
{
ans += edge[j].w;
p[a] = b;
i++;
}
}
cout << ans << endl;
}
return 0;
}