7-1 Werewolf - Simple Version
这是道逻辑题,没太做过类似这种的题目,所以不是很擅长,这题卡了我四十分钟,而且是过掉2,3之后回头才过掉这题的,但其实想来这题还是很简单的。
看题目数据不大,而且狼人和人类中分别必有一人说谎,因此两重循环,每轮假设两个狼人其他均为人类,然后看他们说的话与对应角色的假设身份是否冲突,如果冲突,那么就用掉一次该角色阵营的说谎次数,由于每方只能说谎一次,假如出现了说谎次数不够,就产生冲突,该种假设肯定不成立;反之,直到最后,没产生冲突,而且两阵营的说谎次数必须耗尽,则该假设成立。
#include
using namespace std;
int n;
int sp[105];
int main(){
scanf("%d",&n);
memset(sp,0,sizeof(sp));
for(int i = 1; i <= n; ++i)
scanf("%d",&sp[i]);
int good, wolf;
int mark[105];
for(int i = 1; i < n; ++i){
for(int j = i+1; j <= n; ++j){//i j wolf
memset(mark,1,sizeof(mark));
mark[i] = mark[j] = -1;
good = wolf = 1;
int flag = 0;
for(int k = 1; k <= n; ++k){//sp loop
int tmp = sp[k], pos = abs(tmp);
if((tmp > 0 && mark[pos] > 0) || (tmp < 0 && mark[pos] < 0)){
//buguan
}
else{
if(k == i || k == j){
if(wolf == 1) wolf--;
else {
flag = 1;break;
}
}
else{
if(good == 1) good--;
else {
flag = 1;break;
}
}
}
}
if(!flag && wolf == 0 && good == 0){
printf("%d %d",i,j);
return 0;
}
}
}
printf("No Solution");
return 0;
}
7-2 Dangerous Goods Packaging
这题有点意外,竟然用了个map就过了???我一开始看着很像虚点并查集,但是画了画忘了虚点并查基怎么写了,就想先暴力拿分再说,结果就过了。。。
思路简单明了,将冲突的两种make_pair作为key存入map中,查询的时候,前面输入中没有出现过的直接忽略,出现过的放入一个vector中,后来者就与所有已经存入的比较是否在map中存在这一对,如果存在就冲突。
#include
using namespace std;
int n,m;
map, int> mp;
int vis[100005];
int main(){
scanf("%d%d",&n,&m);
int a, b;
for(int i = 0; i < n; ++i){
scanf("%d%d",&a,&b);
mp[make_pair(a,b)] = 1;
mp[make_pair(b,a)] = 1;
vis[a] = vis[b] = 1;
}
int k,num;
for(int i = 0; i < m; ++i){
scanf("%d",&k);
vector list;
int flag = 1;
for(int j = 0; j < k; ++ j){
scanf("%d",&num);
if(flag == 1){
if(vis[num] == 1){
for(int t = 0; t < list.size(); ++t){
if(mp[make_pair(num,list[t])] == 1){
flag = 0;
break;
}
}
if(flag)
list.push_back(num);
}
}
}
if(flag)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}
7-3 Travelling Salesman Problem (图)
这题更加直白简单,完全就是个代码题吧,没啥好说的。
#include
using namespace std;
const int MAX = 100000;
int N, M;
int g[205][205];
void init(){
for(int i = 0; i < N+2; ++i){
for(int j = 0; j < N+2; ++j){
g[i][j] = g[j][i] = MAX;
}
}
}
struct Ans{
int path, dis;
bool operator < (const Ans &a) const{
return dis < a.dis;
}
};
vector dist;
int main(){
scanf("%d%d",&N,&M);
init();
int a, b, dis;
for(int i = 0; i < M; ++i){
scanf("%d%d%d",&a,&b,&dis);
g[a][b] = g[b][a] = dis;
}
int k, n;
scanf("%d",&k);
for(int cnt = 1; cnt <= k; ++cnt){
scanf("%d",&n);
int tol = 0,origin, pre, cur, flag = 1;
int vis[N+5];
memset(vis,0,sizeof(vis));
scanf("%d",&pre);
origin = pre;
vis[pre] = 1;
for(int i = 1; i < n-1; ++i){
scanf("%d",&cur);
if(g[pre][cur] != MAX){
tol += g[pre][cur];
vis[cur] += 1;
pre = cur;
}
else flag = -1;
}
scanf("%d",&cur);
if(flag == -1 || cur != origin){//not cycle
if(flag == -1)
printf("Path %d: NA (Not a TS cycle)\n",cnt);
else
printf("Path %d: %d (Not a TS cycle)\n",cnt,tol+g[pre][cur]);
}
else{
for(int j = 1; j <= N; ++j){
if(vis[j] == 0){
flag = -1;
}
else if(vis[j] > 1 && flag != -1){
flag = 2;
}
}
if(flag == -1)
printf("Path %d: %d (Not a TS cycle)\n",cnt,tol+g[pre][cur]);
else if(flag == 2){
printf("Path %d: %d (TS cycle)\n",cnt,tol+g[pre][cur]);
Ans tmp;
tmp.path = cnt;
tmp.dis = tol+g[pre][cur];
dist.push_back(tmp);
}
else{
printf("Path %d: %d (TS simple cycle)\n",cnt,tol+g[pre][cur]);
Ans tmp;
tmp.path = cnt;
tmp.dis = tol+g[pre][cur];
dist.push_back(tmp);
}
}
}
sort(dist.begin(),dist.end());
printf("Shortest Dist(%d) = %d\n",dist[0].path,dist[0].dis);
return 0;
}
7-4 LCA in a Binary Tree (LCA+中序先序建二叉树)
其实我至今没想明白,为什么我在考场上一个小时没建出树来,虽说回来后写完了建树的方法,最后没拿满分,但是90+是妥妥的,当时出来真的心态崩了,感觉对不起前面三道题的满分。
这题有两种方法,一种建立二叉树,然后搜,我自己没有想出很好的搜索的方法,因此最后两个case超内存了,反正网上建树的方法多得是,不赘述了。
第二种方法就是不建树,通过中序里子树和其根的关系来搞定,代码简单,易懂。
我们只需要控制三个变量:inl(中序的左边界),inr(中序右边界),pre_root(先序的根结点位置)
然后会有三种情况:1.u,v在中序里都在根的左边或者右边,这就说明他们必然有下一个公共的根。
2.u,v在中序里根的两边,那么这个根就是他们的公共根。
3.u或v位置等于当前根的位置,那么相同位置的就是另一个的根。
LCA的代码:
#include
using namespace std;
int n,m,k;
vector inorder;
vector preorder;
map key2pos;
map vis;
void lca(int inl, int inr, int pre_root, int u, int v){
if(inl > inr) return;
int in_root = key2pos[preorder[pre_root]], uindex = key2pos[u], vindex = key2pos[v];
if(uindex < in_root && vindex < in_root){//left subtree
lca(inl,in_root - 1,pre_root+1,u,v);
}
else if((uindex < in_root && vindex > in_root) || (uindex > in_root && vindex < in_root)){//in_root is root
printf("LCA of %d and %d is %d.\n", u, v, inorder[in_root]);
}
else if(uindex > in_root && vindex > in_root){//right subtree{
lca(in_root+1,inr,pre_root+1+in_root-inl,u,v);
}
else{
if(uindex == in_root) printf("%d is an ancestor of %d.\n", u, v);
else printf("%d is an ancestor of %d.\n", v, u);
}
}
int main(){
scanf("%d%d",&m,&n);
int a;
for(int i = 0; i < n; ++i){
scanf("%d",&a);
inorder.push_back(a);
key2pos[a] = i;
vis[a] = 1;
}
for(int i = 0; i < n; ++i){
scanf("%d",&a);
preorder.push_back(a);
}
int u, v;
for(int i = 0; i < m; ++i){
scanf("%d%d",&u,&v);
if (!vis[u] && !vis[v])
{
printf("ERROR: %d and %d are not found.\n",u,v);
}
else
if (!vis[u])
{
printf("ERROR: %d is not found.\n",u);
}
else
if (!vis[v])
{
printf("ERROR: %d is not found.\n",v);
}
else
{
lca(0,n-1,0,u,v);
}
}
return 0;
}
建树搜索的代码,最后两个case超内存,但主要为了记录下建树,防止下回还TM一小时建不出树:
#include
using namespace std;
int n,m,k;
struct Node{
int h, left, right, data;
Node(){
}
bool operator < (const Node &a) const{
return h < a.h;
}
};
vector inorder;
vector preorder;
Node tree[10005];
map vis;
vector ans;
int build(int prel, int prer, int inl, int inr, int pos, int height){
if(pos >= n) return -1;
tree[pos].h = height;
tree[pos].data = preorder[pos];
tree[pos].left = tree[pos].right = -1;
for(int i = inl; i <= inr; ++i){
if(inorder[i] == preorder[prel]){
if(i > inl){
tree[pos].left = build(prel+1,prel+i-inl,inl,i-1,prel+1,height+1);
}
if(i < inr){
tree[pos].right = build(i-inl+prel+1,prer,i+1,inr,i-inl+prel+1,height+1);
}
}
}
return pos;
}
void finds(int x, int pos, vector path, int &flag){
if(x == tree[pos].data){
path.push_back(tree[pos]);
ans.insert(ans.end(),path.begin(),path.end());
flag = 1;
return;
}
if(flag == 1) return;
path.push_back(tree[pos]);
if(tree[pos].left != -1)
finds(x,tree[pos].left,path,flag);
if(flag == 1) return;
if(tree[pos].right != -1)
finds(x,tree[pos].right,path,flag);
if(flag == 1) return;
}
int main(){
scanf("%d%d",&m,&n);
int a;
for(int i = 0; i < n; ++i){
scanf("%d",&a);
inorder.push_back(a);
vis[a] = 1;
}
for(int i = 0; i < n; ++i){
scanf("%d",&a);
preorder.push_back(a);
}
build(0,n-1,0,n-1,0,1);
int u, v;
for(int i = 0; i < m; ++i){
scanf("%d%d",&u,&v);
if (!vis[u] && !vis[v])
{
printf("ERROR: %d and %d are not found.\n",u,v);
}
else
if (!vis[u])
{
printf("ERROR: %d is not found.\n",u);
}
else
if (!vis[v])
{
printf("ERROR: %d is not found.\n",v);
}
else
{
int flag = 0;
vector tmp1;
finds(u,0,tmp1,flag);
vector tmp2;
flag = 0;
finds(v,0,tmp2,flag);
sort(ans.begin(),ans.end());
int res;
for(int i = 0; i < ans.size(); i += 2){
if(i != ans.size()-1 && ans[i].data == ans[i+1].data){
res = ans[i].data;
}
}
if (res == u) printf("%d is an ancestor of %d.\n",u,v);
else if (res == v) printf("%d is an ancestor of %d.\n",v,u);
else
printf("LCA of %d and %d is %d.\n",u,v,res);
ans.clear();
}
}
return 0;
}
甲级其实完全没有有难度的算法,大部分考的还是数据结构的基础,这次在二叉树上翻了车,想来还是不够扎实吧,12月一定要拿个高分啊。